linux 条件变量函数,Linux线程同步之条件变量
條件變量變量也是出自POSIX線程標(biāo)準(zhǔn),另一種線程同步機(jī)制,。主要用來等待某個(gè)條件的發(fā)生。可以用來同步同一進(jìn)程中的各個(gè)線程。當(dāng)然如果一個(gè)條件變量存放在多個(gè)進(jìn)程共享的某個(gè)內(nèi)存區(qū)中,那么還可以通過條件變量來進(jìn)行進(jìn)程間的同步。
每個(gè)條件變量總是和一個(gè)互斥量相關(guān)聯(lián),條件本身是由互斥量保護(hù)的,線程在改變條件狀態(tài)之間必須要鎖住互斥量。條件變量相對(duì)于互斥量最大的優(yōu)點(diǎn)在于允許線程以無競(jìng)爭(zhēng)的方式等待條件的發(fā)生。當(dāng)一個(gè)線程獲得互斥鎖后,發(fā)現(xiàn)自己需要等待某個(gè)條件變?yōu)檎?#xff0c;如果是這樣,該線程就可以等待在某個(gè)條件上,這樣就不需要通過輪詢的方式來判斷添加,大大節(jié)省了CPU時(shí)間。
在互斥量一文中說過:互斥量是用于上鎖,而不是用于等待;現(xiàn)在這句話可以加強(qiáng)為:互斥量是用于上鎖,條件變量用于等待;
條件變量聲明為pthread_cond_t數(shù)據(jù)類型,在中有具體的定義。
1、條件變量初始化和銷毀
/* Initialize condition variable */
int pthread_cond_init (pthread_cond_t *__restrict __cond,
__const pthread_condattr_t *__restrict __cond_attr) ;
/* Destroy condition variable */
int pthread_cond_destroy (pthread_cond_t *__cond);
上面兩個(gè)函數(shù)分別由于條件變量的初始化和銷毀。
和互斥量的初始化一樣,如果條件變量是靜態(tài)分配的,可以通過常量進(jìn)行初始化,如下:
pthread_cond_t mlock = PTHREAD_COND_INITIALIZER;
也可以通過pthread_cond_init()進(jìn)行初始化,對(duì)于動(dòng)態(tài)分配的條件變量由于不能直接賦值進(jìn)行初始化,就只能采用這種方式進(jìn)行初始化。那么當(dāng)不在需要使用條件變量時(shí),需要調(diào)用pthread_cond_destroy()銷毀該條件所占用的資源。
2、條件變量的屬性設(shè)置
/* 初始化條件變量屬性對(duì)象 */
int pthread_condattr_init (pthread_condattr_t *__attr);
/* 銷毀條件變量屬性對(duì)象 */
int pthread_condattr_destroy (pthread_condattr_t *__attr);
/* 獲取條件變量屬性對(duì)象在進(jìn)程間共享與否的標(biāo)識(shí) */
int pthread_condattr_getpshared (__const pthread_condattr_t * __restrict __attr,
int *__restrict __pshared);
/* 設(shè)置條件變量屬性對(duì)象,標(biāo)識(shí)在進(jìn)程間共享與否 */
int pthread_condattr_setpshared (pthread_condattr_t *__attr, int __pshared) ;
這個(gè)屬性的設(shè)置和互斥量屬性設(shè)置是一樣的,具體使用可以參考互斥量的用法:互斥量的屬性設(shè)置。
3、條件變量的使用
/* 等待條件變?yōu)檎?*/
int pthread_cond_wait (pthread_cond_t *__restrict __cond,
pthread_mutex_t *__restrict __mutex);
/* 限時(shí)等待條件為真 */
int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,
pthread_mutex_t *__restrict __mutex,
__const struct timespec *__restrict __abstime);
/* 喚醒一個(gè)等待條件的線程. */
int pthread_cond_signal (pthread_cond_t *__cond);
/* 喚醒等待該條件的所有線程 */
int pthread_cond_broadcast (pthread_cond_t *__cond);
(1)pthread_cond_wait()函數(shù)用于等待條件被觸發(fā)。該函數(shù)傳入兩個(gè)參數(shù),一個(gè)條件變量一個(gè)互斥量,函數(shù)將條件變量和互斥量進(jìn)行關(guān)聯(lián),互斥量對(duì)該條件進(jìn)行保護(hù),傳入的互斥量必須是已經(jīng)鎖住的。調(diào)用pthread_cond_wait()函數(shù)后,會(huì)原子的執(zhí)行以下兩個(gè)動(dòng)作:
1)將調(diào)用線程放到等待條件的線程列表上,即進(jìn)入睡眠;
2)對(duì)互斥量進(jìn)行解鎖;
由于這兩個(gè)操作時(shí)原子操作,這樣就關(guān)閉了條件檢查和線程進(jìn)入睡眠等待條件改變這兩個(gè)操作之間的時(shí)間通道,這樣就不會(huì)錯(cuò)過任何條件的變化。
當(dāng)pthread_cond_wait()返回后,互斥量會(huì)再次被鎖住。
(2)pthread_cond_timedwait()函數(shù)和pthread_cond_wait()的工作方式相似,只是多了一個(gè)等待時(shí)間。等待時(shí)間的結(jié)構(gòu)為struct
timespec,
/* 等待條件變?yōu)檎?*/
int pthread_cond_wait (pthread_cond_t *__restrict __cond,
pthread_mutex_t *__restrict __mutex);
/* 限時(shí)等待條件為真 */
int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,
pthread_mutex_t *__restrict __mutex,
__const struct timespec *__restrict __abstime);
/* 喚醒一個(gè)等待條件的線程. */
int pthread_cond_signal (pthread_cond_t *__cond);
/* 喚醒等待該條件的所有線程 */
int pthread_cond_broadcast (pthread_cond_t *__cond);
函數(shù)要求傳入的時(shí)間值是一個(gè)絕對(duì)值,不是相對(duì)值,例如,想要等待3分鐘,必須先獲得當(dāng)前時(shí)間,然后加上3分鐘。
要想獲得當(dāng)前系統(tǒng)時(shí)間的timespec值,沒有直接可調(diào)用的函數(shù),需要通過調(diào)用gettimeofday函數(shù)獲取timeval結(jié)構(gòu),然后轉(zhuǎn)換成timespec結(jié)構(gòu),轉(zhuǎn)換公式就是:
/* 等待條件變?yōu)檎?*/
int pthread_cond_wait (pthread_cond_t *__restrict __cond,
pthread_mutex_t *__restrict __mutex);
/* 限時(shí)等待條件為真 */
int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,
pthread_mutex_t *__restrict __mutex,
__const struct timespec *__restrict __abstime);
/* 喚醒一個(gè)等待條件的線程. */
int pthread_cond_signal (pthread_cond_t *__cond);
/* 喚醒等待該條件的所有線程 */
int pthread_cond_broadcast (pthread_cond_t *__cond);
所以要等待3分鐘,timespec時(shí)間結(jié)構(gòu)的獲得應(yīng)該如下所示:
struct timeval now;
struct timespec until;
gettimeofday(&now);//獲得系統(tǒng)當(dāng)前時(shí)間
//把時(shí)間從timeval結(jié)構(gòu)轉(zhuǎn)換成timespec結(jié)構(gòu)
until.tv_sec = now.tv_sec;
until.tv_nsec = now.tv_usec * 1000;
//增加min
until.tv_sec += 3 * 60;
如果時(shí)間到后,條件還沒有發(fā)生,那么會(huì)返回ETIMEDOUT錯(cuò)誤。
從pthread_cond_wait()和pthread_cond_timewait()成功返回時(shí),線程需要重新計(jì)算條件,因?yàn)槠渌€程可能在運(yùn)行過程中已經(jīng)改變條件。
(3)pthread_cond_signal() & pthread_cond_broadcast()
這兩個(gè)函數(shù)都是用于向等待條件的線程發(fā)送喚醒信號(hào),pthread_cond_signal()函數(shù)只會(huì)喚醒等待該條件的某個(gè)線程,pthread_cond_broadcast()會(huì)廣播條件狀態(tài)的改變,以喚醒等待該條件的所有線程。例如多個(gè)線程只讀共享資源,這是可以將它們都喚醒。
這里要注意的是:一定要在改變條件狀態(tài)后,再給線程發(fā)送信號(hào)。
考慮條件變量信號(hào)單播發(fā)送和廣播發(fā)送的一種候選方式是堅(jiān)持使用廣播發(fā)送。只有在等待者代碼編寫確切,只有一個(gè)等待者需要喚醒,且喚醒哪個(gè)線程無所謂,那么此時(shí)為這種情況使用單播,所以其他情況下都必須使用廣播發(fā)送。
下面是一個(gè)測(cè)試代碼,模擬同步問題中經(jīng)典的生產(chǎn)者消費(fèi)者問題。
#include
#include
#include
#include
#include
using namespace std;
//把共享數(shù)據(jù)和它們的同步變量集合到一個(gè)結(jié)構(gòu)中,這往往是一個(gè)較好的編程技巧。
struct{
pthread_mutex_t mutex;
pthread_cond_t cond;
queue product;
}sharedData = {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER};
void * produce(void *ptr)
{
for (int i = 0; i < 10; ++i)
{
pthread_mutex_lock(&sharedData.mutex);
sharedData.product.push(i);
pthread_mutex_unlock(&sharedData.mutex);
if (sharedData.product.size() == 1)
pthread_cond_signal(&sharedData.cond);
//sleep(1);
}
}
void * consume(void *ptr)
{
for (int i = 0; i < 10;)
{
pthread_mutex_lock(&sharedData.mutex);
while(sharedData.product.empty())
pthread_cond_wait(&sharedData.cond, &sharedData.mutex);
++i;
cout<
sharedData.product.pop();
pthread_mutex_unlock(&sharedData.mutex);
//sleep(1);
}
}
int main()
{
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, consume, NULL);
pthread_create(&tid2, NULL, produce, NULL);
void *retVal;
pthread_join(tid1, &retVal);
pthread_join(tid2, &retVal);
return 0;
}
程序的運(yùn)行結(jié)果如下所示:
consume:0
consume:1
consume:2
consume:3
consume:4
consume:5
consume:6
consume:7
consume:8
consume:9
與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的linux 条件变量函数,Linux线程同步之条件变量的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 有没有一些甜品,能够舒缓心情,让人放松的
- 下一篇: windows linux 融合,Win