我在为多线程程序创建和实现计时器方面遇到了麻烦。我创建3个线程,他们应该分别等待1,2和4秒。然而,所有三个线程永远不会停止等待,程序只是无限期地坐在那里。
我需要看看我的两个功能:
CreateAndArmTimer():
-I'我不确定我是否正确使用sigemptyset和sigaddset。我应该"在timer_signal"中创建与所选signal_number相对应的信号掩码。我基本上查看了pthread_sigmask的手册页并复制了我在那里找到的内容。
WaitFortimer():
- 这个功能是导致我的程序无法完成的原因。我的线程正常运行,直到这一点,一旦他们调用这个函数,他们就会陷入其中而永远不会退出。
这两个函数都位于我的代码的底部。我很感激任何帮助!我无法为我的生活做到这一点。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/time.h>
#include <time.h>
#include <string.h>
#include <signal.h>
int threadNumber = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
#define NUM_THREADS 3
//used to store the information of each thread
typedef struct{
pthread_t threadID;
int num;
int policy;
struct sched_param param;
long startTime;
long endTime;
int signal_number;
int missed_signal_count;
int timer_Period;
sigset_t timer_signal;
timer_t timer_Id;
}ThreadInfo;
ThreadInfo myThreadInfo[NUM_THREADS];
void *ThreadRunner(void *vargp);
void CreateAndArmTimer(int unsigned period, ThreadInfo* threadInfo);
void WaitForTimer(ThreadInfo* threadInfo);
int sigwait(const sigset_t* set, int* sig);
int timer_create(clockid_t clockid, struct sigevent* sevp, timer_t* timerid);
//main function
int main(void){
sigset_t alarm_sig;
sigemptyset(&alarm_sig);
for(int i = SIGRTMIN; i <= SIGRTMAX; i++)
sigaddset(&alarm_sig, i);
pthread_sigmask(SIG_BLOCK, &alarm_sig, NULL); //*****apply the blocking*****
printf("\nrunning...\n");
int fifoPri = 60;
//create the 3 fifo threads
for(int i=0; i<NUM_THREADS; i++){
myThreadInfo[i].policy = SCHED_FIFO;
myThreadInfo[i].param.sched_priority = fifoPri++;
pthread_create(&myThreadInfo[i].threadID, NULL, ThreadRunner, &myThreadInfo[i]);
}
printf("\n\n");
sleep(1);
//tell all the threads to unlock
pthread_cond_broadcast(&cond);
//join each thread
for(int g = 0; g < NUM_THREADS; g++){
pthread_join(myThreadInfo[g].threadID, NULL);
}
return 0;
}
//the function that runs the threads
void *ThreadRunner(void *vargp){
struct tm *ts;
struct timeval tv;
size_t last;
time_t timestamp = time(NULL);
threadNumber++;
ThreadInfo* currentThread;
currentThread = (ThreadInfo*)vargp;
currentThread->num = threadNumber;
if(currentThread->num == 1){
currentThread->timer_Period = 1000000;
}
else if(currentThread->num == 2){
currentThread->timer_Period = 2000000;
}
else{
currentThread->timer_Period = 4000000;
}
//lock the thread until it's ready to be unlocked
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
//unlocking for all other threads
pthread_mutex_unlock(&mutex);
if(pthread_setschedparam(pthread_self(), currentThread->policy,(const struct sched_param *) &(currentThread->param))){
perror("pthread_setschedparam failed");
pthread_exit(NULL);
}
if(pthread_getschedparam(pthread_self(), ¤tThread->policy,(struct sched_param *) ¤tThread->param)){
perror("pthread_getschedparam failed");
pthread_exit(NULL);
}
//create and arm the timer
printf("thread#[%d] waiting for %d seconds\n", currentThread->num, (currentThread->timer_Period/1000000));
CreateAndArmTimer(currentThread->timer_Period, currentThread);
//set the start time of the timer
gettimeofday(&tv, NULL);
long startTime = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000;
currentThread->startTime = startTime;
//Wait for the timer
WaitForTimer(currentThread);
//set the end time of the timer
gettimeofday(&tv, NULL);
long endTime = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000;
currentThread->endTime = endTime;
//do the printing
printf("\nThread[%d] Timer Delta[%lu]us Jitter[]us\n", currentThread->num, endTime-startTime);
pthread_exit(NULL);
}
//used to create and arm a new timer
void CreateAndArmTimer(int unsigned period, ThreadInfo* threadInfo){
//Create a static int variable to keep track of the next available signal number
pthread_mutex_lock(&mutex);
static int nextSignalNumber = 0;
if(nextSignalNumber == 0){
nextSignalNumber = SIGRTMIN;
}
else{
nextSignalNumber += 1;
}
pthread_mutex_unlock(&mutex);
threadInfo->signal_number = nextSignalNumber;
//Create the signal mask corresponding to the chosen signal_number in "timer_signal"
//Use "sigemptyset" and "sigaddset" for this
sigemptyset(&threadInfo->timer_signal);
sigaddset(&threadInfo->timer_signal, SIGQUIT);
sigaddset(&threadInfo->timer_signal, SIGUSR1);
//Use timer_Create to create a timer
struct sigevent mySignalEvent;
mySignalEvent.sigev_notify = SIGEV_SIGNAL;
mySignalEvent.sigev_signo = threadInfo->signal_number;
mySignalEvent.sigev_value.sival_ptr = (void*)&(threadInfo->timer_Id);
int ret = timer_create(CLOCK_MONOTONIC, &mySignalEvent, &threadInfo->timer_Id);
if(ret != 0){
printf("error during timer_create for thread#[%d]\n", threadInfo->num);
}
//Arm timer
struct itimerspec timerSpec;
int seconds = period/1000000;
long nanoseconds = (period - (seconds * 1000000)) * 1000;
timerSpec.it_interval.tv_sec = seconds;
timerSpec.it_interval.tv_nsec = nanoseconds;
timerSpec.it_value.tv_sec = seconds;
timerSpec.it_value.tv_nsec = nanoseconds;
int ret2 = timer_settime(threadInfo->timer_Id, 0, &timerSpec, NULL);
if(ret2 != 0){
printf("error with timer_settime!\n");
}
}
//used to make a thread wait for a timer
void WaitForTimer(ThreadInfo* threadInfo){
pthread_sigmask(SIG_UNBLOCK, &threadInfo->timer_signal, NULL); //*****unblock the signal*****
//Use sigwait function to wait on the "timer_signal"
int wait = sigwait(&threadInfo->timer_signal, &threadInfo->signal_number);
if(wait != 0){
printf("error with sigwait!\n");
}
//update missed_signal_count by calling "timer_getoverrun"
threadInfo->missed_signal_count = timer_getoverrun(threadInfo->timer_Id);
}
当我运行它时,输出为:
...运行
线程#[l]等待1秒
线程#[2]等待2秒
线程#[3]等待4秒
答案 0 :(得分:0)
首先,您应该使用pthread_sigmask(2)
而不是sigprocmask(2)
。除了您的注释(指令,如果这是作业?)状态要使用之外,前者在多线程程序中明确指定为POSIX标准的一部分,而后者则不是。我不认为这在Linux上很重要,但它可能是一种很好的做法。
第二个,更重要的是,你并没有真正正确使用这些信号。首先,您通过主函数中sigprocmask(2)
的调用来阻止每个信号,但之后永远不会改变它。在CreateAndArmTimer()
函数中,您实际上从未指定应阻止除之外的所有信号threadInfo->signal_number
。您改为将SIGQUIT
和SIGUSR1
添加到sigset,但之后不会对该集合执行任何操作。你的意思是在这里打电话给pthread_sigmask(2)
吗?如果是这样,您应该确保在此之前添加threadInfo->signal_number
。
关于&#34;听&#34;另外,您实际上 unblock WaitForTimer()
函数(或其他任何地方)中的任何信号。即使您之前已正确阻止它们,如果您在调用sigwait(2)
之前未取消阻止它们,它们也永远不会被传递到您的主题。因此,计时器正在生成所请求的信号,但它们只是位于您的过程的信号队列中。你必须在某处调用pthread_sigmask(SIG_UNBLOCK, ...)
,以便实际交付。
简而言之:
pthread_sigmask(2)
而非sigprocmask(2)
。threadInfo->signal_number
之外的所有信号。sigwait(2)
之前取消阻止这些信号。