使用pthreads进行条件等待

时间:2010-08-26 21:55:36

标签: c pthreads race-condition

我似乎正在使用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 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周期的循环中。我需要主线程来放弃控制和睡眠/等待直到线程退出。

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

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

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

我感谢你的时间。

4 个答案:

答案 0 :(得分:3)

您是否忘记初始化条件变量?

pthread_cond_init(&condVar, NULL)

答案 1 :(得分:0)

  

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()
    ....
}

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

答案 2 :(得分:0)

当代码卡在pthread_cond_wait中时,exit 1 还是 0 ?如果exit 1 ,则应该卡住。

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

1)有些代码将exit设置为 0 ,但没有发出条件变量的信号。

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

答案 3 :(得分:0)

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

为了确保线程已完成(并且其资源已被释放),您应该致电pthread_join()

这里不需要pthread_cond_t

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

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

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()是一个库函数 - 你不应该声明与其他东西同名的任何东西。
  • 根据您的具体情况,保持单个线程始终,并为其提供要执行的作业,而不是连续创建/取消线程(研究'线程池')可能是有意义的