條件變量(Condition Variables)
條件變量是什么?
主線程
| |
線程A
| Thread B
|
主線程
|
創(chuàng)建和銷毀條件變量
函數(shù):
pthread_cond_init (condition,attr) pthread_cond_destroy (condition) pthread_condattr_init (attr) pthread_condattr_destroy (attr) |
用法:
- 靜態(tài)初始化,像這樣聲明:pthread_con_t myconvar = PTHREAD_CON_INITIALIZER;
- 動態(tài)初始化,使用pthread_cond_init()函數(shù)。用創(chuàng)建條件變量的ID作為件參數(shù)傳給線程,這種方法允許設(shè)置條件變量對象屬性 attr。
注意,不是所有的實(shí)現(xiàn)都用得著process-shared屬性。
條件變量的等待和信號發(fā)送
函數(shù):
pthread_cond_wait (condition,mutex) pthread_cond_signal (condition) pthread_cond_broadcast (condition) |
使用:
- 在調(diào)用pthread_cond_wait()之前鎖定互斥量失敗,可致使其無法阻塞;
- 在調(diào)用pthread_cond_signal()之后解鎖互斥量失敗,則致使與之對應(yīng)的pthread_cond_wait()函數(shù)無法完成, 并仍保持阻塞狀態(tài)。
實(shí)例分析
看到下面的一汪代碼不要撓頭,99行而已,之后會抽絲剝繭,目的是對條件變量的運(yùn)行機(jī)制了解個大概:
/******************************************************************************
* 描述:
* 應(yīng)用Pthreads條件變量的實(shí)例代碼,主線程創(chuàng)建三個線程,其中兩個為“count”變量做
* 加法運(yùn)算,第三個線程監(jiān)視“count”的值。當(dāng)“count”達(dá)到一個限定值,等待線程準(zhǔn)備接收來
* 自于兩個加法線程中一個的信號,等待 線程喚醒后更改“count”的值。程序繼續(xù)運(yùn)行直到加法
* 線程達(dá)到TCOUNT的值。最后,主程序打印出count的值。
******************************************************************************/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NUM_THREADS 3
#define TCOUNT 5 //單線程輪詢次數(shù)
#define COUNT_LIMIT 7 //發(fā)送信號的次數(shù)
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的值,如果條件滿足就發(fā)信號給等待線程
* 注意,此處是用信號量鎖定的。
* */
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函數(shù)在等待時將自動以自動原子方式
* 解鎖互斥量。還有,請注意,如果等待線程運(yùn)行到等待函數(shù)之前已經(jīng)滿足COUNT_LIMIT的
* 條件判斷,輪詢會忽略掉等待函數(shù),
* */
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);
/*創(chuàng)建線程時設(shè)為可連接狀態(tài),便于移植*/
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);
}
/*發(fā)送信號給監(jiān)聽線程*/
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做加法運(yùn)算,兩個線程一起做了(2*TCOUNT=)10次運(yùn)算;
- count值小于COUNT_LIMIT時,發(fā)送信號給監(jiān)聽線程;