linux条件变量使用和与信号量的区别
近来在项目中用到条件变量和信号量做同步时,这一块一直都有了解,但也一直没有总结,这次总结一下,给大家提供点参考,也给自己留点纪念。
首先,关于信号量和条件变量的概念可以自行查看APUE,我这直接把APUE中的代码拿过来对比;
一,条件变量的使用:
#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); }
当然,在触发条件变量时也可以用以下代码,两种方式各有优劣,具体可以参考:https://www.cnblogs.com/charlesblc/p/6143397.html
void enqueue_msg(struct msg *mp) { pthread_mutex_lock(&qlock); mp->m_next = workq; workq = mp; pthread_cond_signal(&qready); pthread_mutex_unlock(&qlock); }
二,工作中的使用:
typedef struct _STAT { int b_stop; MDL_COND_T cond; }STAT; STAT g_enc_stat; pthread_mutex_t mutex; pthread_cond_t cond;//可以放在结构体里面 pthread_cond_init(&cond); pthread_mutex_init(&mutex); int dsp_thread_start(unsigned int trmn) { pthread_mutex_lock(&mutex); ... if(1 == g_enc_stat.b_stop) { g_enc_stat.b_stop = 0; pthread_cond_signal(&cond); } pthread_mutex_unlock(&mutex); return OK; } /************************************** * @fn * @brief * @param * @return * @other ***************************************/ int dsp_thread_stop(unsigned int trmn) { pthread_mutex_lock(&mutex); ... g_enc_stat.b_stop = 1; pthread_mutex_unlock(&mutex); return OK; } void dsp_thread(void) {
for(;;)
{
pthread_mutex_lock(&mutex);//不仅用于同步,还可以用于stop时互斥(线程执行时原子操作) if(g_enc_stat.b_stop) { pthread_cond_wait(&cond,&mutex); pthread_mutex_unlock(&mutex);//这个地方也可以不用,参考上述代码,直接执行下面 continue; } . . . pthread_mutex_unlock(&mutex);
} }
三,条件变量和信号量的区别:
(1)使用条件变量可以一次唤醒所有等待者,而这个信号量没有的功能,感觉是最大区别。
(2)信号量是有一个值(状态的),而条件变量是没有的,没有地方记录唤醒(发送信号)过多少次,也没有地方记录唤醒线程(wait返回)过多少次。从实现上来说一个信号量可以是用mutex + counter + condition variable实现的。因为信号量有一个状态,如果想精准的同步,那么信号量可能会有特殊的地方。信号量可以解决条件变量中存在的唤醒丢失问题。
(3)在Posix.1基本原理一文声称,有了互斥锁和条件变量还提供信号量的原因是:“本标准提供信号量的而主要目的是提供一种进程间同步的方式;这些进程可能共享也可能不共享内存区。互斥锁和条件变量是作为线程间的同步机制说明的;这些线程总是共享(某个)内存区。这两者都是已广泛使用了多年的同步方式。每组原语都特别适合于特定的问题”。尽管信号量的意图在于进程间同步,互斥锁和条件变量的意图在于线程间同步,但是信号量也可用于线程间,互斥锁和条件变量也可用于进程间。应当根据实际的情况进行决定。信号量最有用的场景是用以指明可用资源的数量。
经典的一句话:
互斥量是信号量的一种特例,互斥量的本质是一把锁。A mutex is basically a lock that we set (lock) before accessing a shared resource and release (unlock) when we're done
四,互斥锁的巧用:
func a{ lock; temp_time_id = m_time_id; m_time_id = 0; unlock;//不仅减少锁的颗粒度,也能减少死锁,因为detach会等待一个定时器回调,但定时器回调也会加锁,类似于lock->A -> B->lock; if(0 != temp_time_id) CTime::getinstance->detach(temp_time_id) }