在 Linux 多執行緒程式設計中,條件變數是一種用於執行緒間同步的重要機制。它通常與互斥鎖結合使用,用於解決多個執行緒競爭共享資源的問題。條件變數允許一個執行緒在等待某個條件變為真時阻塞,並且在另一個執行緒改變條件並通知時恢復執行。這個玩意跟核心等待佇列差不多意思。
在 Linux 多執行緒程式設計中,使用條件變數進行執行緒同步通常涉及以下幾個相關的函式:
pthread_cond_init: 該函式用於初始化條件變數。 原型為 int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)。 引數 cond 是要初始化的條件變數,attr 是條件變數的屬性,通常為 NULL。 pthread_cond_destroy: 用於銷燬條件變數。 原型為 int pthread_cond_destroy(pthread_cond_t *cond)。 引數 cond 是要銷燬的條件變數。 pthread_cond_wait: 該函式用於等待條件變數的狀態發生變化。 原型為 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)。 引數 cond 是要等待的條件變數,mutex 是與條件變數配合使用的互斥鎖。在呼叫該函式時,執行緒會釋放互斥鎖並阻塞,直到條件變數被其他執行緒發出訊號喚醒。 pthread_cond_timedwait: 類似於 pthread_cond_wait,但是可以設定超時時間,防止永久等待。 原型為 int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)。 pthread_cond_signal: 該函式用於傳送訊號給等待條件變數的一個執行緒。 原型為 int pthread_cond_signal(pthread_cond_t *cond)。呼叫該函式會喚醒等待佇列中的一個執行緒。 pthread_cond_broadcast: 類似於 pthread_cond_signal,但會喚醒等待佇列中的所有執行緒。 原型為 int pthread_cond_broadcast(pthread_cond_t *cond)。
條件變數demo:
在此demo中,有一個生產者執行緒和一個消費者執行緒,它們共享一個整數變數 shared_data。生產者執行緒週期性地增加 shared_data 的值,而消費者執行緒在 shared_data 不為零時消費一個資料。生產者在生產了一個資料後會傳送訊號通知消費者執行緒,消費者在消費資料時需要先檢查條件是否滿足,如果不滿足,則等待條件變為真。
#include <stdio.h> #include <pthread.h> #include <unistd.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; int shared_data = 0; void* producer(void* arg) { while (1) { pthread_mutex_lock(&mutex); shared_data++; // 生產一個資料 printf("Produced: %d\n", shared_data); pthread_cond_signal(&cond); // 傳送訊號通知消費者 pthread_mutex_unlock(&mutex); sleep(1); // 生產者休眠1秒 } return NULL; } void* consumer(void* arg) { while (1) { pthread_mutex_lock(&mutex); while (shared_data == 0) { // 等待條件變為真 pthread_cond_wait(&cond, &mutex); } printf("Consumed: %d\n", shared_data); shared_data--; // 消費一個資料 pthread_mutex_unlock(&mutex); } return NULL; } int main() { pthread_t producer_thread, consumer_thread; pthread_create(&producer_thread, NULL, producer, NULL); pthread_create(&consumer_thread, NULL, consumer, NULL); pthread_join(producer_thread, NULL); pthread_join(consumer_thread, NULL); return 0; }