使用pthreads进行条件等待

我似乎正在使用pthreads条件变量运行可能的死锁。

这是代码

thread function(){ for (condition){ do work /* should the thread continue? */ if (exit == 1){ break; /* exit for */ } } /* end for */ pthread_mutex_lock(&mtxExit); exit = 0; pthread_cond_signal(&condVar); pthread_mutex_unlock(&mtxExit); } 

主要function如下:

 function main(){ if (thread is still active){ pthread_mutex_lock(&mtxExit); exit = 1; pthread_mutex_unlock(&mtxExit); } /* end if */ while (exit == 1){ pthread_mutex_lock(&mtxExit); /* check again */ if (exit == 1) pthread_cond_wait(&condVar, &mtxExit); pthread_mutex_unlock(&mtxExit); } create new thread() .... } 

代码总是卡在cond_wait上。 🙁

编辑:

让我在线程中添加一些说明来解释我在做什么。

在任何给定的时间,我只需要一个线程运行。 我有一个启动线程的函数,告诉它该做什么,主线程继续工作。

下一次主线程决定它需要生成另一个线程时,它必须确保先前启动的线程已退出。 我不能同时拥有两个线程,因为它们会相互干扰。 这是设计和我正在研究的问题的定义。

这就是我遇到问题的地方。

这是我的方法:

启动线程,让它完成它的工作。

线程检查其工作的每一步,看它是否仍然相关。 这是“退出”进入图片的地方。 主线程将“exit”设置为1,如果它需要告诉线程它不再相关。

在大多数情况下,线程将在主线程决定生成另一个线程之前退出。 但是我仍然需要考虑在主线程准备启动另一个线程时线程仍处于活动状态的情况。

所以主线程设置“exit”的值,需要等待线程退出。 我不想使用pthread_kill和0作为信号,因为那时主线程将处于浪费CPU周期的循环中。 我需要主线程来放弃控制和睡眠/等待直到线程退出。

由于我一次只需要一个线程,所以我不需要担心扩展到更multithreading。 解决方案永远不会有多个线程。 我只需要一个可靠的机制来测试我的线程是否仍然存活,如果是,则表示它退出,等待它退出并启动下一个。

从我的测试看起来,主线程仍在进入条件变量,即使线程可能已经退出或者信号根本没有传递到主线程。 它永远在那里等着。 在某些情况下,在调试器中我看到exit的值设置为0,主线程仍在等待信号。 某些地方似乎存在竞争条件。

我不是现在如何设置代码的粉丝,它太乱了。 它现在只是一个概念certificate,我将很快转向更好的解决方案。 我的挑战是可靠地通知线程退出,等待它退出。

我很感激你的时间。

你忘了初始化你的条件变量吗?

 pthread_cond_init(&condVar, NULL) 

while(exit == 1){

在您引用的代码中,您引用的方式我没有看到任何特定问题。 它不干净,但看起来很实用。 是什么让我相信在其他地方你将exit设置为0而没有发出信号。 或者线程在某个地方被卡住了。

但考虑到提示您在启动另一个线程之前尝试发出一个线程终止的注释,我认为你做错了。 如果不能错过信号,通常不应依赖pthread条件信令。 虽然似乎状态变量exit涵盖了这一点,但仍然是IMO错误应用pthread条件。

在这种情况下,您可以尝试使用信号量。 在终止时,线程递增终止信号量,以便main可以等待(递减)信号量。

 thread function() { for (condition) { do work /* should the thread continue? */ if (exit == 1) { break; /* exit for */ } } /* end for */ sem_post(&termSema); } function main() { if (thread is still active) { exit = 1; sem_wait(&termSema); exit = 0; } create new thread() .... } 

作为一般性评论,我可以建议寻找一些线程池实现。 因为使用状态变量来同步线程仍然是错误的,并且不会扩展到多个线程。 而且容易出错。

当代码卡在pthread_cond_waitexit 1还是0 ? 如果exit1 ,则应该卡住。

如果exit0 ,则最有可能出现以下两种情况之一:

1)某些代码集exit0但没有发出条件变量的信号。

2)某些线程在pthread_cond_wait被阻塞,消耗了一个信号,但没有做你需要做的任何事情。

您当前的实现存在各种时序问题(因此存在问题)。

要确保线程已完成(并且其资源已释放),您应该调用pthread_join()

这里不需要pthread_cond_t

使用pthread_cancel()通知线程不再需要它,而不是像你当前正在做的那样,也可能更有意义。

 #include  #include  #include  void *thread_func(void *arg) { int i; for (i = 0; i < 10; i++) { /* protect any regions that must not be cancelled... */ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); /* very important work */ printf("%d\n", i); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); /* force a check to see if we're finished */ pthread_testcancel(); /* sleep (for clarity in the example) */ sleep(1); } return NULL; } void main(void) { int ret; pthread_t tid; ret = pthread_create(&tid, NULL, thread_func, NULL); if (ret != 0) { printf("pthread_create() failed %d\n", ret); exit(1); } sleep(5); ret = pthread_cancel(tid); if (ret != 0) { printf("pthread_cancel() failed %d\n", ret); exit(1); } ret = pthread_join(tid, NULL); if (ret != 0) { printf("pthread_join() failed %d\n", ret); exit(1); } printf("finished...\n"); } 

值得注意的是:

  • exit()是一个库函数 - 你不应该声明任何与其他东西同名的东西。
  • 根据您的具体情况, 始终保持单个线程处于活动状态并为其提供作业可能是有意义的,而不是连续创建/取消线程(研究“线程池”)