條件變數是用來等待執行緒而不是上鎖的,條件變數通常和互斥鎖一起使用。條件變數之所以要和互斥鎖一起使用,主要是因為互斥鎖的乙個明顯的特點就是它只有兩種狀態:鎖定和非鎖定,而條件變數可以通過允許執行緒阻塞和等待另乙個執行緒傳送訊號來彌補互斥鎖的不足,所以互斥鎖和條件變數通常一起使用。
當條件滿足的時候,執行緒通常解鎖並等待該條件發生變化,一旦另乙個執行緒修改了環境變數,就會通知相應的環境變數喚醒乙個或者多個被這個條件變數阻塞的執行緒。這些被喚醒的執行緒將重新上鎖,並測試條件是否滿足。一般來說條件變數被用於執行緒間的同步;當條件不滿足的時候,允許其中的乙個執行流掛起和等待。
簡而言之,條件變數本身不是鎖,但它也可以造成執行緒阻塞,通常與互斥鎖配合使用,給多執行緒提供乙個會合的場所。
條件變數的優點:
相較於mutex而言,條件變數可以減少競爭。如果僅僅是mutex,那麼,不管共享資源裡有沒資料,生產者及所有消費都全一窩蜂的去搶鎖,會造成資源的浪費。
如直接使用mutex,除了生產者、消費者之間要競爭互斥量以外,消費者之間也需要競爭互斥量,但如果匯聚(鍊錶)中沒有資料,消費者之間競爭互斥鎖是無意義的。有了條件變數機制以後,只有生產者完成生產,才會引起消費者之間的競爭。提高了程式效率。
主要應用函式:
pthread_cond_init函式
pthread_cond_destroy函式
pthread_cond_wait函式
pthread_cond_timedwait函式
pthread_cond_signal函式
pthread_cond_broadcast函式
以上6 個函式的返回值都是:成功返回0, 失敗直接返回錯誤號。
pthread_cond_t型別:用於定義條件變數,比如:pthread_cond_t cond;
函式原型:
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
函式作用:
初始化乙個條件變數
引數說明:
cond:條件變數,呼叫時應傳&cond給該函式
attr:條件變數屬性,通常傳null,表示使用預設屬性
也可以使用靜態初始化的方法,初始化條件變數:
pthread_cond_t cond = pthread_cond_initializer;
函式原型:
int pthread_cond_destroy(pthread_cond_t *cond);
函式作用:
銷毀乙個條件變數
函式原型:
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
函式作用:
阻塞等待乙個條件變數。具體而言有以下三個作用:
阻塞等待條件變數cond(參1)滿足;
釋放已掌握的互斥鎖mutex(解鎖互斥量)相當於pthread_mutex_unlock(&mutex);
當被喚醒,pthread_cond_wait函式返回時,解除阻塞並重新申請獲取互斥鎖
其中1、2.兩步為乙個原子操作。
函式原型:
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
函式作用:
限時等待乙個條件變數
引數說明:
前兩個比較好理解,重點說明第三個引數。
這裡有個struct timespec結構體,可以在man sem_timedwait中檢視。結構體原型如下:
struct timespec ;
pthread_cond_timedwait (&cond, &mutex, &t);
這種用法只能定時到 2023年1月1日 00:00:01秒,想必這個時間大家都還沒出生。
正確用法:
time_t cur = time(null); 獲取當前時間。
struct timespec t; 定義timespec 結構體變數t
t.tv_sec = cur+1; 定時1秒
pthread_cond_timedwait (&cond, &mutex, &t); 傳參
函式原型:
int pthread_cond_signal(pthread_cond_t *cond);
函式作用:
喚醒至少乙個阻塞在條件變數上的執行緒
函式原型:
int pthread_cond_broadcast(pthread_cond_t *cond);
函式作用:
喚醒全部阻塞在條件變數上的執行緒
不管是什麼語言,只要提到執行緒同步,乙個典型的案例就是生產者消費者模型。在linux環境下,借助條件變數來實現這一模型,是比較常見的一種方法。
假定有兩個執行緒,乙個模擬生產者行為,乙個模擬消費者行為。兩個執行緒同時操作乙個共享資源(一般稱之為匯聚),生產向其中新增產品,消費者從中消費掉產品。
看如下示例,使用條件變數模擬生產者、消費者問題:
#include #include #include #include typedef struct msg msg_t;
msg_t *head = null;
msg_t *mp = null;
/* 靜態初始化 乙個條件變數 和 乙個互斥量*/
pthread_cond_t has_product = pthread_cond_initializer;
pthread_mutex_t mutex =pthread_mutex_initializer;
void *th_producer(void *arg)
return null;
}void *th_consumer(void *arg)
mp = head;
head = mp->next; //模擬消費掉乙個產品
pthread_mutex_unlock(&mutex);
printf("*****==== consume: %d *****=\n", mp->num);
free(mp);
mp = null;
sleep(rand() % 5);
}return null;
}int main()
執行結果:
Linux系統程式設計 條件變數
條件變數是用來等待執行緒而不是上鎖的,條件變數通常和互斥鎖一起使用。條件變數之所以要和互斥鎖一起使用,主要是因為互斥鎖的乙個明顯的特點就是它只有兩種狀態 鎖定和非鎖定,而條件變數可以通過允許執行緒阻塞和等待另乙個執行緒傳送訊號來彌補互斥鎖的不足,所以互斥鎖和條件變數通常一起使用。當條件滿足的時候,執...
Linux系統程式設計 條件變數 互斥量
基於unix環境高階程式設計,不懂條件變數執行流程的一定要看 後面的白字,重要 以下討論建立在互斥量已經理解的前提。條件變數這裡卡了我很久,總算理清邏輯,趕快總結一波 乙個重要的函式pthread cond wait pthread cond t,pthread mutex t 這裡,令這兩種pth...
Linux系統程式設計之執行緒條件變數
include include include include pthread cond t cond pthread cond initializer 初始化條件變數 pthread mutex t mutex pthread mutex initializer 靜態初始化互斥鎖 struct m...