pthread_cond_wait 丢失来自 pthread_cond_signal 的信号

Posted

技术标签:

【中文标题】pthread_cond_wait 丢失来自 pthread_cond_signal 的信号【英文标题】:pthread_cond_wait lost signal from pthread_cond_signal 【发布时间】:2014-04-08 14:20:36 【问题描述】:

我创建了多个线程并希望使用条件变量以循环方式运行它们 和信号(pthread_cond_wait & pthread_cond_signal)。

我使用了两种方法,一种方法有效但浪费 CPU,而另一种方法无效, 不浪费 CPU。

我面临的问题是信号之前发送 我的线程在等待并且信号丢失了。所以它进入无限等待循环。

第一种方法:

线程被创建并等待条件变量并不断检查调用的变量 作为状态(在一个while循环内)。

当 state == my_id 时,带有 my_id 的线程被激活,然后它向下一个线程 my_id+1 发出信号,依此类推 开。

DRAWBACK : CPU 的浪费

第二种方法:

线程被创建并等待它自己的条件变量的信号。现在因为信号已经 在线程开始等待之前发送,信号丢失,程序进入无限等待循环。

信号丢失时是否有类似“自我信号”或其他发送信号的方式?

我在linux下使用g++。任何线索将不胜感激。提前致谢。

第一种方法的程序在这里round robin。

这是我的第二种方法的程序:

#include <pthread.h>
#include <stdio.h>
#include <iostream>
#include <mutex>          // std::mutex


#define MULTIPLE_THREADS 2
#define NTHREADS MULTIPLE_THREADS*64
#define NO_OF_LOOP 1


pthread_cond_t      cond[NTHREADS];
pthread_mutex_t     mutex1 = PTHREAD_MUTEX_INITIALIZER;


using namespace std;



/* This is our thread function.  It is like main(), but for a thread*/
void *threadA(void *arg)
 
    long my_id = (long)arg;
    int i = 0;

    while(i < NO_OF_LOOP)
    


        // Awaken or unblocked by thread (i-1) 
        pthread_mutex_lock(&mutex1);
        pthread_cond_wait(&cond[my_id], &mutex1);
        pthread_mutex_unlock(&mutex1);

        printf("I am thread - %ld",my_id);
        ++i;


         /* wake up thread i+1 */
        pthread_mutex_lock(&mutex1);
        pthread_cond_signal(&cond[(my_id + 1) % NTHREADS]);
        pthread_mutex_unlock(&mutex1);      
    

    return NULL;


int main(void)


    pthread_t             threadid[NTHREADS];


    // Initialization   
    for(int i=0;i<NTHREADS;i++)
    cond[i]= PTHREAD_COND_INITIALIZER;

    //printf("Create %d threads\n", NTHREADS);
    for(long i=0; i<NTHREADS; ++i) 
    pthread_create(&threadid[i], NULL, threadA, (void *)i);
    //printf("Thread created=%d\n", i);
    

    //  printf("Wait for threads and cleanup\n");
    for (long i=0; i<NTHREADS; ++i) 
    pthread_join(threadid[i], NULL);
    

    return 0;

【问题讨论】:

重新设计!在等待之前不要发出信号。 @Dabo 以后如何发送信号?我应该在主线程中使用一些睡眠吗? 您的互斥锁没有保护任何东西,您的线程也没有等待任何东西。 【参考方案1】:

您不能以这种方式使用条件变量。你总是需要一个谓词。也就是说,你需要 您可以测试是否发生事件的变量。

简单地发出一个盲目的 pthread_cond_wait 和 pthread_cond_signal 会让你丢失事件。 可能有spurious wakeups,如果你发信号的线程没有在pthread_cond_wait()中被阻塞,它将错过事件(pthread_cond_signal()没有排队)。

您将需要这样的东西(未经测试):

pthread_cond_t      cond[NTHREADS];
int                 wakeup[NTHREADS];
pthread_mutex_t     mutex1 = PTHREAD_MUTEX_INITIALIZER;


using namespace std;



/* This is our thread function.  It is like main(), but for a thread*/
void *threadA(void *arg)
 
    long my_id = (long)arg;
    int i = 0;

    while(i < NO_OF_LOOP)
    


        // Awaken or unblocked by thread (i-1) 
        pthread_mutex_lock(&mutex1);
        while (!wakeup[my_id]) 
            pthread_cond_wait(&cond[my_id], &mutex1);
        
        wakeup[my_id] = 0;
        pthread_mutex_unlock(&mutex1);

        printf("I am thread - %ld",my_id);
        ++i;

        pthread_mutex_lock(&mutex1);
        //tell thread i to wake up
        wakeup[(my_id + 1) % NTHREADS] = 1; 
        pthread_cond_signal(&cond[(my_id + 1) % NTHREADS]);
        pthread_mutex_unlock(&mutex1);      
    

    return NULL;

int main(void)


    pthread_t             threadid[NTHREADS];
    wakeup[0] = 1; //let thread 0 start.

编辑。 #define NTHREADS MULTIPLE_THREADS*64 宏也有另一个错误。 表达式(my_id + 1) % NTHREADS 将不会被正确计算,宏必须是

 #define NTHREADS (MULTIPLE_THREADS*64)

由于标准输出通常是行缓冲的,所以在你的 printf 中添加一个换行符,这样你就可以立即看到输出。

 printf("I am thread - %ld\n",my_id);

【讨论】:

感谢您解释我在第一种方法中使用的条件变量谓词的需要,您也提出了类似的建议。我有一个疑问或疑问-您不认为在检查谓词时会浪费大量 CPU 吗?顺便说一句,虽然看起来逻辑是正确的(我使用了相同的逻辑,除了我只使用了一个状态变量)但是你的代码不起作用。 @bholanath 没有浪费 CPU,pthread_cond_wait() 阻塞了线程。我不知道如何通过只有一个状态变量来完成这项工作(而且我也不确定你的意思,听起来你只有 1 个变量而不是像唤醒数组这样的数组 - 这将不行)。注意 main() 中的wakeup[0] = 1; 相当重要。 我猜它会部分因为 #define NTHREADS MULTIPLE_THREADS*64 宏,因为它不会做你想让它做的事情。始终使用括号:#define NTHREADS (MULTIPLE_THREADS*64) 我已经更改了宏,现在它正在输出。谢谢。顺便说一句,这里使用多个变量(如数组)有什么用,因为我正在使用单个变量(即状态)获取输出并检查 state == my_id 是否? 是的,我想在这个例子中这很好,如果你只想要顺序执行,只有一个具有执行 ID 的变量会这样做

以上是关于pthread_cond_wait 丢失来自 pthread_cond_signal 的信号的主要内容,如果未能解决你的问题,请参考以下文章

为什么pthread_cond_wait须要传递mutex參数

条件变量使用总结

pthread_cond_wait() 同时唤醒两个线程

TopCoder 最佳选择算法来自 SRM 489 DIV 2 (500 pt)

多核处理器上的 pthread_cond_wait 问题

pthread_cond_wait虚假唤醒