1、需求
有消费者A和生产者B线程,共享变量n,生存者对n++,消费者对n--,消费者线程A必须要等到n>0才可以执行下去,当然生产者B线程就执行n++,让消费者能执行下去。
2、生产者和消费者模型中互斥锁和条件变量的使用流程图如下,其中蓝色代表消费者的执行流,红色是生产者的执行流。
3、几个函数
/* 初始化一个条件变量 */
int pthread_cond_init (pthread_cond_t* cond, pthread_condattr_t *cond_attr);
/* 销毁一个条件变量 */
int pthread_cond_destroy(pthread_cond_t* cond);
/* 令一个消费者等待在条件变量上 */
int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex)
/* 生产者通知等待在条件变量上的消费者 */
int pthread_cond_signal(pthread_cond_t* cond);
/* 生产者向消费者广播消息 */
int pthread_cond_broadcast(pthread_cond_t* cond);
消费者等待条件的伪代码:
pthread_mutex_lock(&mutex); // 拿到互斥锁,进入临界区
while( 条件为假)
pthread_cond_wait(cond, mutex); // 令进程等待在条件变量上
修改条件
pthread_mutex_unlock(&mutex); // 释放互斥锁
生产者通知消费者的伪代码:
pthread_mutex_lock(&mutex); // 拿到互斥锁,进入临界区
while( 条件为假)
pthread_cond_wait(cond, mutex); // 令进程等待在条件变量上
修改条件
pthread_mutex_unlock(&mutex); // 释放互斥锁
4、实例代码
/***************************************************************
* Copyright (C) 2016 chengonghao
* All rights reserved.
*
* chengonghao@yeah.net
***************************************************************/
#include <unistd.h>
#include <pthread.h>
#define CONSUMERS_COUNT 2
#define PRODUCERS_COUNT 1
pthread_mutex_t g_mutex ;
pthread_cond_t g_cond ;
pthread_t g_thread[CONSUMERS_COUNT + PRODUCERS_COUNT] ;
int share_variable = 0 ;// this is the share variable, shared by consumer and producer
void* consumer( void* arg )
{
int num = (int)arg ;
while ( 1 )
{
/******* critical section begin *******/
pthread_mutex_lock( &g_mutex ) ;
// if share_variable == 0, means consumer shell stop here
while ( share_variable == 0 )
{
printf( "consumer %d begin wait a condition...\n", num ) ;
// put a thread blocked ont a condition variable( here is g_cond),
// and unlock the mutex( here is g_mutex )
pthread_cond_wait( &g_cond, &g_mutex ) ;
}
// here means n != 0 and consumer can goes on
// consumer consumed shared variable, so the number of shared variable shell minus
printf( "consumer %d end wait a condition...\n", num ) ;
printf( "consumer %d begin consume product\n", num ) ;
-- share_variable ;
pthread_mutex_unlock( &g_mutex ) ;
/******** critial section end *********/
sleep( 1 ) ;
}
return NULL ;
}
void* producer( void* arg )
{
int num = (int)arg ;
while ( 1 )
{
/******* critical section begin *******/
pthread_mutex_lock( &g_mutex ) ;
// produce a shared variable
printf( "producer %d begin produce product...\n", num ) ;
++ share_variable ;
printf( "producer %d end produce product...\n", num ) ;
// unblock threads blocked on a condition variable( here is g_cond )
pthread_cond_signal( &g_cond ) ;
printf( "producer %d notified consumer by condition variable...\n", num ) ;
pthread_mutex_unlock( &g_mutex ) ;
/******** critial section end *********/
sleep( 5 ) ;
}
return 1 ;
}
int main( void )
{
// initiate mutex
pthread_mutex_init( &g_mutex, NULL ) ;
// initiate condition
pthread_cond_init( &g_cond, NULL ) ;
// initiate consumer threads
for ( int i = 0; i < CONSUMERS_COUNT; ++ i )
{
pthread_create( &g_thread[i], NULL, consumer, (void*)i ) ;
}
sleep( 1 ) ;
// initiate producer threads
for ( int i = 0; i < PRODUCERS_COUNT; ++ i )
{
pthread_create( &g_thread[i], NULL, producer, (void*)i ) ;
}
for ( int i = 0; i < CONSUMERS_COUNT + PRODUCERS_COUNT; ++ i )
{
pthread_join( g_thread[i], NULL ) ;
}
pthread_mutex_destroy( &g_mutex ) ;
pthread_cond_destroy( &g_cond ) ;
}
5、执行结果
1. 第一个框,消费者 1 和0 发现share_variable == 0,于是先后等待在条件变量上;
2. 第二个框,生产者 0 开始生产共享变量,即 ++ share_variable,然后通知等待在条件变量上的消费者;
3. 第三个框,消费者 1 被生产者唤醒,开始消费共享变量,即– share_variable;
4. 第四个框,生产者 0 继续生产共享变量,++ share_variable,然后通知等待在条件变量上的消费者;
5. 第五个框,消费者 0 被唤醒,开始消费共享变量,即– share_variable;
以此类推,以上描述简化了拿锁和释放锁的过程,可以结合上面的流程图来理解代码。