Linux執行緒---執行緒同步互斥:條件變數
阿新 • • 發佈:2019-01-11
使用互斥鎖可實現執行緒間資料的共享和通訊,互斥鎖的一個明顯的缺點是它只有兩種狀態:鎖定和非鎖定。二條件變數通過允許執行緒阻塞和等待另一個執行緒傳送訊號的方法彌補了互斥鎖的不足,它常和互斥鎖一起使用。
使用時,條件變數被用來阻塞一個執行緒,當條件不滿足時,執行緒往往解開相應的互斥鎖並等待條件發生變化。一旦其它的某個執行緒改變了條件變數,相應的條件變數喚醒一個或多個正被此條件變數阻塞的執行緒。這些執行緒將重新鎖定互斥鎖屏重新測試條件是否滿足。
一個簡單的例子
count為0時,decrement_count中的pthread_cond_wait處被阻塞,並解鎖count_lock。此時,當呼叫到increment_count時,pthread_cond_signal改變條件變數,告知decrement_count停止阻塞。
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
pthread_mutex_t count_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t count_nonzero = PTHREAD_COND_INITIALIZER;
int count = 0;
void decrement_count()
{
while(1)
{
pthread_mutex_lock(&count_lock);
while (count == 0)
// 該條件獲得訊號之前,該函式一直被阻塞
// 該函式會在被阻塞之前以原子方式釋放互斥鎖count_lock
// 並導致呼叫執行緒基於count_nonzero所指向的條件變數阻塞
// 在返回之前以原子方式再次獲取該互斥鎖
// 當該執行緒更改條件值時,另一個執行緒會針對條件變數發出訊號
// 這種變化會導致所有等待該條件的執行緒解除阻塞並嘗試再次獲取互斥鎖
// 喚醒的執行緒重新獲取互斥鎖並從pthread_cond_wait()返回之前,
// 條件可能會發生變化
// 建議使用的測試方法是,將條件檢查編寫為呼叫pthread_cond_wait()的while()迴圈
pthread_cond_wait(&count_nonzero, &count_lock);
count = count - 1;
printf("decrement: %d\n", count);
pthread_mutex_unlock(&count_lock);
sleep(1);
}
}
void increment_count()
{
while(1)
{
pthread_mutex_lock(&count_lock);
if(count == 0)
// 解除count_nonzero所指向的條件變數阻塞的執行緒
// 應在互斥鎖的保護下修改相關條件
pthread_cond_signal(&count_nonzero);
count = count + 1;
printf("increment: %d\n", count);
pthread_mutex_unlock(&count_lock);
sleep(1);
}
}
int main()
{
pthread_t de, in;
pthread_create(&de, NULL, (void*)decrement_count, NULL);
pthread_create(&in, NULL, (void*)increment_count, NULL);
pthread_join(de, NULL);
pthread_join(in, NULL);
pthread_mutex_destroy(&count_lock);
pthread_cond_destroy(&count_nonzero); // 銷燬條件變數狀態
return 0;
}
1個生產者—1個消費者
需要互斥地訪問記憶體
當記憶體滿,生產者不能生產,生產者生產後,喚醒消費者
當記憶體空,消費者不能消費,消費者消費了產品後,喚醒生產者
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
int count = 0;
int maxcount = 5;
pthread_mutex_t count_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t less = PTHREAD_COND_INITIALIZER;
pthread_cond_t more = PTHREAD_COND_INITIALIZER;
void producer()
{
while(1)
{
pthread_mutex_lock(&count_lock);
while(count > maxcount)
pthread_cond_wait(&less, &count_lock);
count = count + 1;
printf("producer: %d\n", count);
pthread_cond_signal(&more);
pthread_mutex_unlock(&count_lock);
usleep(1000);
}
}
void consumer()
{
while(1)
{
pthread_mutex_lock(&count_lock);
while(count <= 0)
pthread_cond_wait(&more, &count_lock);
count = count - 1;
printf("consumer: %d\n", count);
pthread_cond_signal(&less);
pthread_mutex_unlock(&count_lock);
usleep(1000);
}
}
int main()
{
pthread_t pro, con;
pthread_create(&pro, NULL, (void*)producer, NULL);
pthread_create(&con, NULL, (void*)consumer, NULL);
pthread_join(pro, NULL);
pthread_join(con, NULL);
pthread_mutex_destroy(&count_lock);
pthread_cond_destroy(&less);
pthread_cond_destroy(&more);
return 0;
}