文章目錄
- 條件變量
- 概述
- 條件變量的優缺點
- 條件變量相關函數
- pthread_cond_init函數
- pthread_cond_destroy函數
- pthread_cond_wait函數
- pthread_cond_signal函數
- 測試生產者和消費者模型
條件變量
概述
與互斥鎖不同,條件變量是用來等待而不是用來上鎖的,條件變量本身不是鎖!
條件變量用來自動阻塞一個線程,直到某特殊情況發生為止。通常條件變量和互斥鎖同時使用。
條件變量的兩個動作:
- 條件不滿, 阻塞線程
- 當條件滿足, 通知阻塞的線程開始工作
條件變量的類型: pthread_cond_t。
條件變量的優缺點
相較于mutex而言,條件變量可以減少競爭。
如直接使用mutex,除了生產者、消費者之間要競爭互斥量以外,消費者之間也需要競爭互斥量,但如果匯聚(鏈表)中沒有數據,消費者之間競爭互斥鎖是無意義的。
有了條件變量機制以后,只有生產者完成生產,才會引起消費者之間的競爭。提高了程序效率。
條件變量相關函數
pthread_cond_init函數
#include <pthread.h>
?
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
功能:初始化一個條件變量
參數:cond:指向要初始化的條件變量指針。attr:條件變量屬性,通常為默認值,傳NULL即可也可以使用靜態初始化的方法,初始化條件變量:pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
返回值:成功:0失敗:非0錯誤號
pthread_cond_destroy函數
#include <pthread.h>
?
int pthread_cond_destroy(pthread_cond_t *cond);
功能:銷毀一個條件變量
參數:cond:指向要初始化的條件變量指針
返回值:成功:0失敗:非0錯誤號
pthread_cond_wait函數
#include <pthread.h>
?
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
功能:阻塞等待一個條件變量a) 阻塞等待條件變量cond(參1)滿足b) 釋放已掌握的互斥鎖(解鎖互斥量)相當于pthread_mutex_unlock(&mutex);a) b) 兩步為一個原子操作。c) 當被喚醒,pthread_cond_wait函數返回時,解除阻塞并重新申請獲取互斥鎖pthread_mutex_lock(&mutex);
?
參數:cond:指向要初始化的條件變量指針mutex:互斥鎖
?
返回值:成功:0失敗:非0錯誤號
?
int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct.*restrict abstime);
功能:限時等待一個條件變量
?
參數:cond:指向要初始化的條件變量指針mutex:互斥鎖abstime:絕對時間
?
返回值:成功:0失敗:非0錯誤號
abstime補充說明:
struct timespec {time_t tv_sec; /* seconds */ // 秒long tv_nsec; /* nanosecondes*/ // 納秒
}
?
time_t cur = time(NULL); //獲取當前時間。
struct timespec t; //定義timespec 結構體變量t
t.tv_sec = cur + 1; // 定時1秒
pthread_cond_timedwait(&cond, &t);
pthread_cond_signal函數
#include <pthread.h>
?
int pthread_cond_signal(pthread_cond_t *cond);
功能:喚醒至少一個阻塞在條件變量上的線程
參數:cond:指向要初始化的條件變量指針
返回值:成功:0失敗:非0錯誤號
?
int pthread_cond_broadcast(pthread_cond_t *cond);
功能:喚醒全部阻塞在條件變量上的線程
參數:cond:指向要初始化的條件變量指針
返回值:成功:0失敗:非0錯誤號
測試生產者和消費者模型
#include <stdio.h>
#include <string.h>
#include <stdlib.h> #include <unistd.h>
#include <pthread.h>pthread_cond_t cond;
pthread_mutex_t mutex;typedef struct _node_t
{int data;struct _node_t *next;
}node_t;node_t *head = NULL;void *producer(void *arg)
{node_t *new = NULL;while(1){pthread_mutex_lock(&mutex);new = malloc(sizeof(node_t));if(NULL == new){printf("malloc failed\n");pthread_mutex_unlock(&mutex);break;}memset(new, 0, sizeof(node_t));new->data = random() % 100 + 1;new->next = head;head = new;printf("-------生產者生產了產品 %d\n", new->data);pthread_mutex_unlock(&mutex);pthread_cond_signal(&cond);sleep(random() % 3 + 1);}pthread_exit(NULL);
}void *customer(void *arg)
{node_t *tmp = NULL;while(1){pthread_mutex_lock(&mutex);if(NULL == head){//阻塞在條件變量pthread_cond_wait(&cond, &mutex);}//刪除鏈表第一個節點tmp = head;head = head->next;printf("消費者消費產品 %d\n", tmp->data);free(tmp);pthread_mutex_unlock(&mutex);sleep(random() % 3 + 1);}pthread_exit(NULL);
}
int test01()
{int ret = -1;pthread_t tid1 = -1;pthread_t tid2 = -1;srandom(time(NULL));ret = pthread_mutex_init(&mutex, NULL);if(0 != ret){printf("pthread_mutex_init failed\n");goto err0;}ret = pthread_cond_init(&cond, NULL);if(0 != ret){printf("pthread_cond_init failed\n");goto err0;}//生產者線程ret = pthread_create(&tid1, NULL, producer, NULL);if(0 != ret){printf("pthread_create failed\n");goto err0;}//消費者線程ret = pthread_create(&tid1, NULL, customer, NULL);if(0 != ret){printf("pthread_create failed\n");goto err0;}pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);return 0;
err0:return 1;
}