pthread_cond_signal该放在什么地方?

时间:2022-09-28 19:09:33
 pthread_cond_signal()的具体位置?
"pthread_cond_signal()必须要放在pthread_mutex_lock() 和pthread_mutex_unlock() 之间, " 我认为这个做法有个问题,举个例子

简单假设线程1、2,curnum 值为 1, 语句执行顺序如下:
                                                     
T2-->;pthread_mutex_lock(&mutex_curnum);                
T2-->;while(curnum)                                     
T2-->;  pthread_cond_wait(&cond_curnum,&mutex_curnum);/*T2解锁,睡眠,等信号*/  
T1-->;pthread_mutex_lock(&mutex_curnum);              /*轮T1运行,T1上锁*/                                                     
T1-->;if (!-curnum)                                  /*条件成立*/  
T1-->;    pthread_cond_signal(&cond_curnum);          /*T1向线程T2发信号*/  
T2-->;pthread_cond_wait(&cond_curnum,&mutex_curnum);  /*T1时间片用完,换T2执行,但发觉不能上锁,因为T1持有锁*/                                                        
T1-->;pthread_mutex_unlock(&mutex_curnum);            /*T1解锁*/  

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 问题在于一个条件变量和一个互斥锁关联, 一个线程在持有锁的情况下调用pthread_cond_signal(), 则等待条件的线程有可能得不到锁。

就上面的特定例子来,配合每条语句的执行顺序,
虽然T1调用了pthread_cond_signal(), 但是T2 100%不能获得锁。

《UNIX网络编程第2卷:进程间通信》提了一个改进方法
pthread_mutex_lock();  
判断是否别个线程等待的条件发生,是的话设 "发生标志""";  
pthread_mutex_unlock();   
if (发生标志 == 是)  
{  
    pthread_cond_signal(...);  
}  
例子如下:
shows an example of how to use condition variables and mutexes together to synchronize threads.
The condition is the state of the work queue. We protect the condition with a mutex and evaluate the condition in a while loop. When we put a message on the work queue, we need to hold the mutex, but we don't need to hold the mutex when we signal the waiting threads. As long as it is okay for a thread to pull the message off the queue before we call cond_signal, we can do this after releasing the mutex. Since we check the condition in a while loop, this doesn't present a problem: a thread will wake up, find that the queue is still empty, and go back to waiting again. If the code couldn't tolerate this race, we would need to hold the mutex when we signal the threads.
gure 11.14. Using condition variables
#include <pthread.h>

struct msg {
    struct msg *m_next;
    /* ... more stuff here ... */
};
struct msg *workq;
pthread_cond_t qready = PTHREAD_COND_INITIALIZER;
pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER;

void
process_msg(void)
{
    struct msg *mp;

    for (;;) {
        pthread_mutex_lock(&qlock);
        while (workq == NULL)
            pthread_cond_wait(&qready, &qlock);
        mp = workq;
        workq = mp->m_next;
        pthread_mutex_unlock(&qlock);
        /* now process the message mp */
    }
}

void
enqueue_msg(struct msg *mp)
{
    pthread_mutex_lock(&qlock);
    mp->m_next = workq;
    workq = mp;
    pthread_mutex_unlock(&qlock);
    pthread_cond_signal(&qready);
}


pthread_cond_wait必须放在pthread_mutex_lock和pthread_mutex_unlock之间,
因为他要根据共享变量的状态来觉得是否要等待,而为了不永远等待下去所以必须要在lock/unlock队中
共享变量的状态改变必须遵守lock/unlock的规则

pthread_cond_signal即可以放在pthread_mutex_lock和pthread_mutex_unlock之间,
也可以放在pthread_mutex_lock和pthread_mutex_unlock之后,但是各有有缺点。

之间:
pthread_mutex_lock
    xxxxxxx
pthread_cond_signal
pthread_mutex_unlock
缺点:在某下线程的实现中,会造成等待线程从内核中唤醒(由于cond_signal)然后又回到内核空间
(因为cond_wait返回后会有原子加锁的行为),所以一来一回会有性能的问题。
但是在LinuxThreads或者NPTL里面,就不会有这个问题,因为在Linux 线程中,
有两个队列,分别是cond_wait队列和mutex_lock队列, cond_signal只是
让线程从cond_wait队列移到mutex_lock队列,而不用返回到用户空间,不会有性能的损耗。
所以在Linux中推荐使用这种模式。

之后:
pthread_mutex_lock
    xxxxxxx
pthread_mutex_unlock
pthread_cond_signal
优点:不会出现之前说的那个潜在的性能损耗,因为在signal之前就已经释放锁了
缺点:如果unlock在signal之前,有个低优先级的线程正在mutex上等待的话,
那么这个低优先级的线程就会抢占高优先级的线程(cond_wait的线程),
而这在上面的放中间的模式下是不会出现的。

所以,在Linux下最好pthread_cond_signal放中间,但从编程规则上说,其他两种都可以
(但我认为pthread_cond_signal放中间那样是不可以的)
转载自:http://blog.csdn.net/dove1984/article/details/7996085