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