使用sigev_notify = SIGEV_THREAD_ID方法的POSIX计时器

multithreading场景中,我试图实现一个POSIX计时器,在计时器到期时,应该唤醒同一进程的下一个线程(一次只有一个线程正在运行,而其他所有线程都处于阻塞状态)。 在计时器中,我使用sigev_notify = SIGEV_THREAD_ID既不希望任何处理程序服务的信号,也不想在计时器到期后创build一个新的线程。

//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); } 

编译: $ gcc filename.c -lrt -lpthread

我已经使用信号来同步线程,以便线程以特定的顺序执行。

我没有得到所需的输出。 它应该像在15微秒后,计时器应该过期,下一个线程应该被唤醒,但不会发生。 我用sigwait()来阻塞线程。 有没有其他的select来阻止一个线程,并使用定时器唤醒他们? signum中可以分配的信号是什么? 我可以使用pthread_cond_signal()而不是SIGALRM吗?

嗯..好的。

初始化你的信号量到一个单位,让所有的线程等待它。

如果一个线程获得单元,它将当前的“startTime”时间存储在某个静态/ gobal /任何(安全的,因为一次只有一个线程可以拥有semaunit),然后离开去做它的事情。 完成后,它得到endTime的endTime时间,将endTime-startTime的时间花费多长时间,然后从所需的线程间隔时间中减去这个时间 – 现在在下一个线程可以运行之前还剩多少时间 – remainingInterval”。 如果remainingInterval小于0,则它使它为0.它将remainingInterval转换为usleep()/ Sleep()所需的任何单位并休眠那么长时间,然后将其单位发送到信号量。 然后可以运行另一个线程,并且刚刚完成其工作的线程可以循环并等待信号量(如果希望的话)。

无论多久/排序/无论工作如何,都不可能一次运行多个线程。

没有明确的计时器,互斥,condvar等是必需的,只有一个信号量。

您期望所有线程在定时器到期时以顺序方式一次发送一个信号,但定时器设置(timer_settime)已在所有线程中完成,这违反了规则。

这是需要做的事情:定时器和时间的设置,需要在进程级别单次发生,而不是每个线程。

接下来,创建所有线程,并将线程标识符存储在数组中,并根据某些条件(pthread_cond_wait)使其等待。

当定时器到期并发送一个信号时,通过thread-id循环唤醒,一次一个线程。