Çok işlemcili bir senaryoda, aynı işlemin sonraki iş parçacığının uyandırılması gereken (yalnızca bir iş parçacığının çalıştığı ve tüm diğerleri) bir POSIX zamanlayıcıyı uygulamaya çalışıyorum. blok halindedir). Zamanlayıcıda, sigev_notify = SIGEV_THREAD_ID numaralı telefonu kullanıyorum, çünkü herhangi bir işleyicinin sinyale hizmet vermesini istemiyorum veya zamanlayıcı sona erdikten sonra yeni bir iş parçacığı oluşturmak istiyorum.POSIX zamanlayıcı ile sigev_notify = SIGEV_THREAD_ID yöntemi
//Import
#define _GNU_SOURCE
#define _POSIX_C_SOURCE 199309
#include <sched.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <syscall.h>
#define NUM_THREADS 10
#define CLOCKID CLOCK_REALTIME
int ret;
//pthread_cond_t condA[NUM_THREADS+1] = PTHREAD_COND_INITIALIZER;
pthread_cond_t condA = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
sem_t sem[NUM_THREADS];
sem_t mute;
timer_t timer1;
pthread_t tid[NUM_THREADS];
int state = 0;
int thread_count = 1;
int arr_tid[NUM_THREADS];
struct itimerspec new_value, old_value;
struct sigaction action;
struct sigevent sevent;
sigset_t set;
int signum = SIGALRM;
void *threadA(void *data_)
{
cpu_set_t my_set;
CPU_ZERO(&my_set);
CPU_SET(2, &my_set);
sched_setaffinity(0, sizeof(cpu_set_t), &my_set);
//struct itimerspec new_value, old_value;
int i = 0, value;
int sid;
FILE *fp;
fp=fopen("ipc.out","a");
long int loopNum;
int turn = (intptr_t)data_;
struct timespec tval_result, tval_result2;
if(thread_count < NUM_THREADS)
{
thread_count++;
sid = syscall(SYS_gettid);
arr_tid[turn] = sid;
fprintf(fp,"thread_%d %d\n", turn, sid);
//printf("Blocked %d ->%d\n", turn, thread_count);
pthread_mutex_lock(&mutex);
pthread_cond_wait(&condA, &mutex);
pthread_mutex_unlock(&mutex);
}
else
{
arr_tid[turn] = syscall(SYS_gettid);
}
for (value = 0; value < NUM_THREADS; ++value)
{
printf("%d\n",arr_tid[value]);
}
//printf("rpg\n");
pthread_mutex_lock(&mutex);
pthread_cond_broadcast(&condA);
pthread_mutex_unlock(&mutex);
//printf("unblocked\n");
fclose(fp);
if (turn > 0)
{
if (sigwait (&set, &signum) == -1)
perror ("sigwait");
//sleep(1);
//printf("thread %d is sleeping\n", turn);
}
while(1)
{
ret = sem_wait(&sem[turn]);
if (ret)
{
printf("Error in Sem Post\n");
}
//printf("this isn't the end of the world!!!\n");
sevent.sigev_notify = SIGEV_THREAD_ID;
sevent._sigev_un._tid = arr_tid[(turn+1)%10];
sevent.sigev_signo = signum;
sigemptyset(&set);
sigaddset(&set, signum);
sigprocmask(SIG_BLOCK, &set, NULL);
printf("Thread # -> %d\n", turn);
clock_gettime(CLOCKID, &tval_result);
do
{
clock_gettime(CLOCKID, &tval_result2);
} while((tval_result2.tv_sec - tval_result.tv_sec)*1000000000+(tval_result2.tv_nsec - tval_result.tv_nsec)<=12000);
//printf("Timestamp : %ld %ld\n", tval_result2.tv_sec, tval_result2.tv_nsec);
// printf("Before creating timer\n");
new_value.it_interval.tv_sec = 0;
new_value.it_interval.tv_nsec = 0;
new_value.it_value.tv_sec = 0;
new_value.it_value.tv_nsec = 15000;
printf("next thread to be signalled %d\n", arr_tid[turn+1]);
if (timer_settime (timer1, 0, &new_value, NULL) == -1)
perror ("timer_settime");
printf("yy\n");
ret = sem_post(&sem[(state+1)%NUM_THREADS]);
if (ret)
{
printf("Error in Sem Post\n");
}
state++;
//printf("yy\n");
//sleep(1);
if (sigwait (&set, &signum) == -1)
perror ("sigwait");
}
}
int main(int argc, char *argv[])
{
int data = 0;
int err, i;
int sid = syscall(SYS_gettid);
//struct itimerspec new_value, old_value;
FILE *fp;
fp=fopen("ipc.out","a");
fprintf(fp,"Mainthread %d\n",sid);
fclose(fp);
if (timer_create (CLOCK_REALTIME, &sevent, &timer1) == -1)
perror ("timer_create");
sem_init(&sem[0], 0, 1);
//sem_init(&sem[1], 0, 0);
//sem_init(&sem[2], 0, 0);
for (i = 1; i < NUM_THREADS; ++i)
{
sem_init(&sem[i], 0, 0);
}
while(data < NUM_THREADS)
{
//create our threads
err = pthread_create(&tid[data], NULL, threadA, (void *)(intptr_t)data);
if(err != 0)
printf("\ncan't create thread :[%s]", strerror(err));
data++;
}
pthread_exit(NULL);
}
Derleme:$ gcc filename.c -lrt -lpthread Ben ipler belirli bir sırayla çalıştırmak, böylece konuları eşitlemek için semaforları kullandık
.
İstenilen çıktıyı alamıyorum. 15 mikrosaniyeden sonra olması gerektiği gibi olmalıdır, zamanlayıcı sona ermeli ve sonraki iplik uyanmalı ama gerçekleşmiyor. Konuları engellemek için sigwait() kullandım. Bir iş parçacığını engellemek ve bir zamanlayıcı kullanarak onları uyandırmak için başka alternatifler var mı? signum'da atanabilen sinyaller nelerdir? SIGALRM yerine pthread_cond_signal() kullanabilir miyim?
Küçük bir anlamsız görünüyor .... –
@MartinJames Sigwait() man sayfasına göre, sinyali beklemek için sinyal bekleyen herhangi bir sayıda iplik alınabilir.Benim durumumda hangisi istenmiyor ki. Yani, zamanlayıcı son kullanma tarihinde bir ipliği özel olarak uyandırmak için bir mekanizma varsa, o zaman benim sorunum için yeterli olacaktır. (pthread_cond_signal() öğesinde, bir koşul değişkeninde bekleyen belirli bir iş parçacığına sinyal gönderebildiğimiz gibi) – Scissor