为什么pthread_cond_signal有时不起作用?

时间:2014-11-28 15:21:22

标签: c multithreading pthreads signals

我的程序执行"线程同步"使用pthread_cond_waitpthread_cond_signal。它似乎在20次中失败了一次。

我有一个共享变量count,它被初始化为0。 一个线程递增count直到count为20,然后发出条件变量信号。

代码如下。

void* inc_count(void *parm)
{
    int i;
    for(i = 0 ; i <25; i ++)// adds count to 25
    {
        pthread_mutex_lock(&mutex1);
        count ++;
        printf("Thread %lld , count = %d\n",(long long int)pthread_self(),count);
        if(count == 20)
        {
            pthread_cond_signal(&cond);
            printf("Thread %lld sends a signal!\n",(long long int)pthread_self());
        }
        pthread_mutex_unlock(&mutex1);
    }
    pthread_exit(NULL);
}

void* watch_count(void *parm)
{

    while(count < 20)
    {   
        pthread_mutex_lock(&mutex1);    
        pthread_cond_wait(&cond,&mutex1);
        printf("Thread %lld receives the signal!\n",(long long int)pthread_self());
    }
    pthread_mutex_unlock(&mutex1);
    pthread_exit(NULL);
}
int main()
{
    pthread_t pt1,pt2,pt3,pt4;
    pthread_mutex_init(&mutex1,NULL);
    pthread_mutex_init(&mutex2,NULL);
    pthread_cond_init(&cond,NULL);
    pthread_create(&pt1,NULL,inc_count,NULL);
    pthread_create(&pt2,NULL,watch_count,NULL);
    pthread_join(pt1,NULL);
    pthread_join(pt2,NULL);

}

从图片中,您可以看到线程pt2没有收到信号,为什么?

2 个答案:

答案 0 :(得分:3)

您的watch_count()功能有问题:

  • 您将互斥锁锁定在while循环内并且仅在其外部解锁(可以尝试锁定多次而不解锁)
  • 检查count < 20
  • 时,您不会持有互斥锁

要修复它,您需要在循环之前而不是在其中锁定互斥锁:

pthread_mutex_lock(&mutex1);    
while(count < 20)
{   
    pthread_cond_wait(&cond,&mutex1);
    printf("Thread %lld receives the signal!\n",(long long int)pthread_self());
}
pthread_mutex_unlock(&mutex1);

这样可以防止您在解锁之前多次锁定互斥锁,并确保count无法修改,并且无法在{{1}的测试之间发送信号条件和whilepthread_cond_wait&#39;更改为inc_count()并且发送信号必须在while循环之前或count期间发生)。

即使进行了这些更改,如果pthread_cond_wait()count检查它的时候watch_count()已经是20,那么等待仍然可能会发生。< / p>

答案 1 :(得分:1)

在他的评论结束时,@ Dmitri的诊断是可能的崇拜IMO:在inc_count线程首次检查之前,你的watch_count线程有可能超过20 while条件。

为什么要使用while循环?当inc_count发送信号时,您已经知道计数超过20,那么为什么要检查呢?

我的解决方案是进行一些握手,确保watch_countinc_count开始计数之前进入等待状态。为此,您需要确保按顺序执行以下操作:

  1. inc_count首先输入其代码,然后等待watch_count初始化
  2. watch_count输入其代码并发出inc_count已准备就绪的信号
  3. watch_count等待inc_count发出信号
  4. inc_count开始计数,并在watch_count到达20
  5. 时发出信号

    我通过在启动任一线程之前获取互斥锁来实现此目的,然后依靠第一个线程进入其&#34;准备好等待&#34;在开始第二个线程之前的条件。当第二个线程准备就绪时,它会指示第一个线程继续开始计数,这是我的代码:

    void* inc_count(void *parm)
    {
        // holding this mutex on entry;
        pthread_mutex_t* m = parm;
        int i;
    
        // wait for the watch_count thread to be ready
        pthread_cond_wait(&init_cond, m);
        pthread_mutex_unlock(m);
    
        // start counting
        for(i = 0 ; i < 10000; i ++)
        {
            pthread_mutex_lock(&count_mutex);
            count++;
            printf("Thread %lld , count = %d\n", 
                           (long long int) pthread_self(),
                           count);
    
            if(count == 20)
            {
                pthread_cond_signal(&count_cond);
                printf("Thread %lld sends a signal!\n",
                               (long long int)pthread_self());
            }
            pthread_mutex_unlock(&count_mutex);
        }
        pthread_exit(NULL);
    }
    
    void* watch_count(void *parm)
    {
        // holding this mutex on entry
        pthread_mutex_t* m = parm;
    
        pthread_cond_signal(&init_cond);   // tell inc_count that you're ready
        pthread_cond_wait(&count_cond,m);  // wait for him to get to 20
        pthread_mutex_unlock(m);
    
        pthread_mutex_lock(&count_mutex);
        printf("Thread %lld receives the signal! count == %d\n",
                       (long long int)pthread_self(), 
                       count);
        pthread_mutex_unlock(&count_mutex);
    
        pthread_exit(NULL);
    }
    
    int main()
    {
        pthread_t pt1,pt2;
        pthread_mutex_t init_mutex, count_mutex;
    
        pthread_mutex_init(&init_mutex,NULL);
        pthread_mutex_init(&count_mutex,NULL);
        pthread_cond_init(&init_cond,NULL);
        pthread_cond_init(&count_cond,NULL);
    
        // this mutex is released when inc_count has initialized
        pthread_mutex_lock(&init_mutex);
        pthread_create(&pt1,NULL,inc_count,(void *) &init_mutex);
    
        // this mutex is released when watch-count has initialized
        pthread_mutex_lock(&init_mutex);
        pthread_create(&pt2,NULL,watch_count,(void *) &init_mutex);
    
        pthread_join(pt1,NULL);
        pthread_join(pt2,NULL);
    }