为了便于理解,画了个图,一系列动作完成下来只需要一个mutex和一个conditional_variable。
wait函数包含了很多操作,在wait之前和之后必须要手动加锁/解锁mutex,保证同一时间只有一个人对条件变量cond进行使用。
先unlock或者先发送signal()都可以,Linux推荐吧signal()包在中间。
注意,即便以及发送了signal,却没有unlock,那么及时wait收到了信号,也无法返回,因为wait最后还需要锁住mutex,没抢到的话,只能在那继续阻塞。
pthread conditional_variable:
cond_wait: (usage:) lock -> cond_wait -> unlock
(在调用wait时阻塞住线程,等待cond_signal的通知)
What's inside the function wait()? It unlocks the mutex and then blocks the thread.
The purpose of lock is to prevent simultaneous requests of wait().
If cond_signal happens, it will stop blocking and lock the mutex automatically.
cond_signal: (usage:) lock -> cond_signal -> unlock
here, lock and unlock means you have to write them explicitly in code by using pthread_mutex_lock
下面列出一个Demo:
#include <stdio.h>
C代码 :
#include <stdlib.h>
#include <pthread.h>
struct msg{
struct msg *next;
int num;
};
struct msg *head;
pthread_cond_t has_product;//Condition Variable
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;//互斥锁初始化
void *consumer(void *p)
{
struct msg *mp;
for(;;){
pthread_mutex_lock(&lock);//保证生产与消费的互斥,消费者取得lock
while(head == NULL)
pthread_cond_wait(&has_product,&lock);
/*其实while这一过程并不是必需的, pthread_cond_wait这一过程已经可以实现等待-执行可程了.但由于线程被唤醒的情况有多种,我们需要的是head!=NULL这种情况才会继续执行.而且pthread_cond_wait()这个方法还会有一个内在的执行过程,在pthread_cond_wait()这一过程中我们必需保证lock的持有,当线程刷新了等待队列之后,在被持起之前lock会被释放.
当另一个线程调用pthread_cond_signal()唤醒之前需要先把lock给释放了,因为调用pthread_cond_signal()后,消费进程需要重新通过pthread_cond_wait()这个方法获得lock,然后执行逻辑处理代码,最后消费进程释放lock.*/
mp = head;
head = mp->next;
pthread_mutex_unlock(&lock);//释放lock
printf("Consumer %d\n",mp->num);
free(mp);
sleep(rand()%5);
}
}
void *producer(void *p)
{
struct msg *mp;
for(;;){
mp = malloc(sizeof(struct msg));
mp->num = rand() % 1000+1;
printf("Produce %d\n",mp->num);
pthread_mutex_lock(&lock);//为保证操作的原子性获得lock
mp->next = head;
head = mp;
pthread_mutex_unlock(&lock);//释放lock
pthread_cond_signal(&has_product);//唤醒消费进程
sleep(rand()%5);
}
}
int main(int argc,char *argv[])
{
pthread_t pid,cid;
srand(time(NULL));
cid = pthread_create(&cid,NULL,consumer,NULL);
pid = pthread_create(&pid,NULL,producer,NULL);
sleep(5);
pthread_join(pid,NULL);
pthread_join(cid,NULL);
return 0;
}