条件变量(Condition Variables)
条件变量是什么?
主线程
|
|
线程A
|
Thread B
|
主线程
|
创建和销毁条件变量
函数:
pthread_cond_init (condition,attr) pthread_cond_destroy (condition) pthread_condattr_init (attr) pthread_condattr_destroy (attr) |
用法:
- 静态初始化,像这样声明:pthread_con_t myconvar = PTHREAD_CON_INITIALIZER;
- 动态初始化,使用pthread_cond_init()函数。用创建条件变量的ID作为件参数传给线程,这种方法允许设置条件变量对象属性attr。
注意,不是所有的实现都用得着process-shared属性。
条件变量的等待和信号发送
函数:
pthread_cond_wait (condition,mutex) pthread_cond_signal (condition) pthread_cond_broadcast (condition) |
使用:
- 在调用pthread_cond_wait()之前锁定互斥量失败,可致使其无法阻塞;
- 在调用pthread_cond_signal()之后解锁互斥量失败,则致使与之对应的pthread_cond_wait()函数无法完成,并仍保持阻塞状态。
实例分析
看到下面的一汪代码不要挠头,99行而已,之后会抽丝剥茧,目的是对条件变量的运行机制了解个大概:
/* *****************************************************************************
* 描述:
* 应用Pthreads条件变量的实例代码,主线程创建三个线程,其中两个为“count”变量做
* 加法运算,第三个线程监视“count”的值。当“count”达到一个限定值,等待线程准备接收来
* 自于两个加法线程中一个的信号,等待 线程唤醒后更改“count”的值。程序继续运行直到加法
* 线程达到TCOUNT的值。最后,主程序打印出count的值。
***************************************************************************** */
#include < pthread.h >
#include < stdio.h >
#include < stdlib.h >
#define NUM_THREADS 3
#define TCOUNT 5 // 单线程轮询次数
#define COUNT_LIMIT 7 // 发送信号的次数
int count = 0 ; // 全局的累加量
pthread_mutex_t count_mutex;
pthread_cond_t count_threshold_cv;
void * inc_count( void * t) {
int i;
long my_id = ( long ) t;
for (i = 0 ; i < TCOUNT; i ++ ) {
pthread_mutex_lock( & count_mutex);
count ++ ;
/*
* 检查count的值,如果条件满足就发信号给等待线程
* 注意,此处是用信号量锁定的。
* */
if (count < COUNT_LIMIT) {
printf( " inc_count(): thread %ld, count = %d Threshold reached. " ,
my_id, count);
pthread_cond_signal( & count_threshold_cv);
printf( " Just sent signal.\n " );
}
printf( " inc_count(): thread %ld, count = %d, unlocking mutex\n " , my_id,
count);
pthread_mutex_unlock( & count_mutex);
/* 为线程轮询互斥锁增加延时 */
sleep( 1 );
}
pthread_exit(NULL);
}
void * watch_count( void * t) {
long my_id = ( long ) t;
printf( " Starting watch_count(): thread %ld\n " , my_id);
/* 锁定互斥量并等待信号,注意,pthread_cond_wait函数在等待时将自动以自动原子方式
* 解锁互斥量。还有,请注意,如果等待线程运行到等待函数之前已经满足COUNT_LIMIT的
* 条件判断,轮询会忽略掉等待函数,
* */
while (count < COUNT_LIMIT) {
pthread_mutex_lock( & count_mutex);
printf( " watch_count(): thread %ld going into wait...\n " , my_id);
pthread_cond_wait( & count_threshold_cv, & count_mutex);
printf( " watch_count(): thread %ld Condition signal received.\n " , my_id);
printf( " watch_count(): thread %ld count now = %d.\n " , my_id, count);
pthread_mutex_unlock( & count_mutex);
}
pthread_exit(NULL);
}
int main( int argc, char * argv[]) {
int i;
long t1 = 1 , t2 = 2 , t3 = 3 ;
pthread_t threads[ 3 ];
pthread_attr_t attr;
/* 初始化互斥量和条件变量对象 */
pthread_mutex_init( & count_mutex, NULL);
pthread_cond_init( & count_threshold_cv, NULL);
/* 创建线程时设为可连接状态,便于移植 */
pthread_attr_init( & attr);
pthread_attr_setdetachstate( & attr, PTHREAD_CREATE_JOINABLE);
pthread_create( & threads[ 0 ], & attr, watch_count, ( void * ) t1);
pthread_create( & threads[ 1 ], & attr, inc_count, ( void * ) t2);
pthread_create( & threads[ 2 ], & attr, inc_count, ( void * ) t3);
/* 等待所有线程完成 */
for (i = 1 ; i < NUM_THREADS; i ++ ) {
pthread_join(threads[i], NULL);
}
/* 发送信号给监听线程 */
pthread_cond_signal( & count_threshold_cv);
pthread_join(threads[ 0 ],NULL);
printf( " Main(): Waited on %d threads. Final value of count = %d. Done.\n " ,
NUM_THREADS, count);
/* 清除并退出 */
pthread_attr_destroy( & attr);
pthread_mutex_destroy( & count_mutex);
pthread_cond_destroy( & count_threshold_cv);
pthread_exit(NULL);
}
- 两个线程利用互斥量为count做加法运算,两个线程一起做了(2*TCOUNT=)10次运算;
- count值小于COUNT_LIMIT时,发送信号给监听线程;
# Pthreads
Starting watch_count(): thread 1
watch_count(): thread 1 going into wait...
inc_count(): thread 2 , count = 1 Threshold reached. Just sent signal.
inc_count(): thread 2 , count = 1 , unlocking mutex
watch_count(): thread 1 Condition signal received.
watch_count(): thread 1 count now = 1 .
watch_count(): thread 1 going into wait...
inc_count(): thread 3 , count = 2 Threshold reached. Just sent signal.
inc_count(): thread 3 , count = 2 , unlocking mutex
watch_count(): thread 1 Condition signal received.
watch_count(): thread 1 count now = 2 .
watch_count(): thread 1 going into wait...
inc_count(): thread 2 , count = 3 Threshold reached. Just sent signal.
inc_count(): thread 2 , count = 3 , unlocking mutex
watch_count(): thread 1 Condition signal received.
watch_count(): thread 1 count now = 3 .
watch_count(): thread 1 going into wait...
inc_count(): thread 3 , count = 4 Threshold reached. Just sent signal.
inc_count(): thread 3 , count = 4 , unlocking mutex
watch_count(): thread 1 Condition signal received.
watch_count(): thread 1 count now = 4 .
watch_count(): thread 1 going into wait...
inc_count(): thread 2 , count = 5 Threshold reached. Just sent signal.
inc_count(): thread 2 , count = 5 , unlocking mutex
watch_count(): thread 1 Condition signal received.
watch_count(): thread 1 count now = 5 .
watch_count(): thread 1 going into wait...
inc_count(): thread 3 , count = 6 Threshold reached. Just sent signal.
inc_count(): thread 3 , count = 6 , unlocking mutex
watch_count(): thread 1 Condition signal received.
watch_count(): thread 1 count now = 6 .
watch_count(): thread 1 going into wait...
inc_count(): thread 2 , count = 7 , unlocking mutex
inc_count(): thread 3 , count = 8 , unlocking mutex
inc_count(): thread 2 , count = 9 , unlocking mutex
inc_count(): thread 3 , count = 10 , unlocking mutex
watch_count(): thread 1 Condition signal received.
watch_count(): thread 1 count now = 10 .
Main(): Waited on 3 threads. Final value of count = 10 . Done.