//创建一个互斥对象
//初始化一个互斥锁;
原型:
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *attr);
//加锁,如果不成功,阻塞等待;
原型:
int pthread_mutex_lock(pthread_mutex_t *mutex);
//解锁;
原型:
int pthread_mutex_unlock(pthread_mutex_t *mutex);
//测试加锁,非阻塞的锁定互斥锁,如果不成功就立即返回,错误码为EBUSY;
原型:
int pthread_mutex_trylock( pthread_mutex_t *mutex );
//注销一个互斥锁;
原型:
int pthread_mutex_destroy(pthread_mutex_t *mutex);
1. 问题: 互斥锁一个明显的缺点是他只有两种状态:锁定和非锁定,所以经常导致死锁。
2. 解决: 解决死锁的方案就是采用条件变量。
3. 条件变量的作用: 条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,他常和互斥锁一起使用。
条件变量: cond
是线程同步的一种手段。
其用来阻塞一个线程,直到条件为真为止。一般和互斥量同时使用。
1. 使用:
一个/多个线程等待"条件变量的条件成立"而挂起;
另一个线程使"条件成立"信号。
2. 具体实现:
3. 作用:
1. /* 初始化一个条件变量 */
int pthread_cond_init (pthread_cond_t* cond, pthread_condattr_t *cond_attr);
2. /* 销毁一个条件变量 */
int pthread_cond_destroy(pthread_cond_t* cond);
3. /* 令一个消费者等待在条件变量上 */
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
4. /* 生产者通知等待在条件变量上的消费者 */
int pthread_cond_signal(pthread_cond_t* cond);
1. 调用pthread_cond_wait前需要先对互斥量mutex上锁,
才能把&mutex传入pthread_cond_wait函数
3. 在pthread_cond_wait函数内部,会首先对传入的mutex解锁
4. 当等待的条件到来后,pthread_cond_wait函数内部在返回前会去锁住传入的mutex
In Thread1:消费者
pthread_mutex_lock(&mutex); // 拿到互斥锁,进入临界区
while( 条件为假)
pthread_cond_wait(cond, mutex); // 令进程等待在条件变量上
//修改条件
pthread_mutex_unlock(&mutex); // 释放互斥锁
In Thread2:生产者
pthread_mutex_lock(&mutex); // 拿到互斥锁,进入临界区
//设置条件为真
pthread_cond_signal(cond); // 通知等待在条件变量上的消费者
pthread_mutex_unlock(&mutex); // 释放互斥锁
2. 通俗易懂说
妈妈负责做饭,你负责吃,你从饭桌上夹菜吃饭
如果饭桌上有饭,则你去吃,此时妈妈等你吃完再做
如果饭桌没饭了,则妈妈去做饭,此时你需要等妈妈做完再吃
生产者生产物品,消费者消费物品。
所谓生产者-消费者问题,实际上主要是包含了两类线程,一种是生产者线程用于生产数据,另一种是消费者线程用于消费数据;为了解耦生产者和消费者的关系;
通常会采用共享的数据区域,就像是一个仓库,生产者生产数据之后直接放置在共享数据区中,并不需要关心消费者的行为;而消费者只需要从共享数据区中去获取数据,就不再需要关心生产者的行为。
但是,这个共享数据区域中应该具备这样的线程间并发协作的功能:
#include
#include
#include
#define CONSU_THREAD_COUNT 4 //消费者线程数目
#define PRO_THREAD_COUNT 3 //生产者线程数目
//互斥量,条件变量定义
pthread_mutex_t g_mutex ;
pthread_cond_t g_cond ;
pthread_t g_thread[CONSU_THREAD_COUNT + PRO_THREAD_COUNT ] ;
//全局变量,产品
//生产者生产产品(g_iProduct 加1),消费者消费产品(g_iProduct 减1)
int g_iProduct = 0;
//消费者线程
void* consumer_thread( void* arg )
{
int iThread_Num = *(int *)arg ;
while ( 1 )
{
//加锁
pthread_mutex_lock( &g_mutex ) ;
//如果没有产品,即g_iProduct 为0,则消费者需要等待产品生产完成,才能消费
while ( g_iProduct == 0 )
{
printf( "consumer %d begin wait a condition...\n", iThread_Num ) ;
// 使线程阻塞在 条件变量这里,等待条件变量就绪
/*
VIP !!!
当pthread_cond_wait被调用线程阻塞的时候,pthread_cond_wait会自动释放互斥锁。
具体:
1. 调用pthread_cond_wait前需要先对互斥量mutex上锁,
才能把&mutex传入pthread_cond_wait函数
2. 在pthread_cond_wait函数内部,会首先对传入的mutex解锁
3. 当等待的条件到来后,
pthread_cond_wait函数内部在返回前会去锁住传入的mutex
*/
pthread_cond_wait( &g_cond, &g_mutex ) ;
}
// 跳出while循环,说明生产者将产品生产完成,g_iProduct != 0
//产品消费完毕,减1
--g_iProduct ;
printf( "consumer %d Consumer...\n", iThread_Num ) ;
//解锁
pthread_mutex_unlock( &g_mutex ) ;
//等待
sleep( 1 ) ;
}
return NULL;
}
//生产者线程
void* producer_thread( void* arg )
{
int iThread_Num = *(int *)arg ;
while ( 1 )
{
//加锁
pthread_mutex_lock( &g_mutex ) ;
// 生产者生产产品,g_iProduct 加1
++ g_iProduct;
printf( " +++ producer %d make ...\n", iThread_Num ) ;
//通知等待在条件变量上的消费者
pthread_cond_signal( &g_cond ) ;
//解锁
pthread_mutex_unlock( &g_mutex ) ;
sleep( 1 ) ;
}
return NULL ;
}
//测试函数
void main()
{
int iLoop = 0;
//互斥量,条件变量初始化
pthread_mutex_init( &g_mutex, NULL ) ;
pthread_cond_init( &g_cond, NULL ) ;
//创建消费者线程
for ( iLoop = 0; iLoop < CONSU_THREAD_COUNT; ++ iLoop )
{
pthread_create( &g_thread[iLoop ], NULL, consumer_thread, (void*)&iLoop ) ;
sleep( 1 ) ;
}
//创建生产者线程
for (iLoop = 0; iLoop < PRO_THREAD_COUNT; ++ iLoop )
{
pthread_create( &g_thread[iLoop ], NULL, producer_thread, (void*)&iLoop ) ;
sleep( 1 ) ;
}
//等待消费者和生产者线程结束
for (iLoop = 0; iLoop < CONSU_THREAD_COUNT + PRO_THREAD_COUNT; ++ iLoop )
{
pthread_join( g_thread[iLoop ], NULL ) ;
}
//销毁互斥量和条件变量
pthread_mutex_destroy( &g_mutex ) ;
pthread_cond_destroy( &g_cond ) ;
return ;
}
结果:
[root@localhost home]# gcc -lpthread mutextTest.c
[root@localhost home]# ./a.out
consumer 0 begin wait a condition...
consumer 1 begin wait a condition...
consumer 2 begin wait a condition...
consumer 3 begin wait a condition...
+++ producer 0 make ...
consumer 0 Consumer...
consumer 0 begin wait a condition...
+++ producer 0 make ...
consumer 1 Consumer...
+++ producer 1 make ...
consumer 2 Consumer...
+++ producer 0 make ...
consumer 1 Consumer...
+++ producer 1 make ...
consumer 2 Consumer...
consumer 3 begin wait a condition...
consumer 0 begin wait a condition...
+++ producer 2 make ...
consumer 3 Consumer...
+++ producer 0 make ...
consumer 1 Consumer...
+++ producer 1 make ...
consumer 2 Consumer...
+++ producer 2 make ...
consumer 3 Consumer...
consumer 0 begin wait a condition...
^C
[root@localhost home]#