(1) 條件變量是鎖?
不是鎖, 但是條件變量能夠阻塞線程, 調用阻塞函數開始阻塞
使用條件變量+互斥量
互斥量: 保護一塊共享數據----> 保護數據
條件變量: 引起阻塞, 生產者和消費者模型----> 阻塞線程
(2) 條件變量的兩個動作
條件不滿足: 阻塞線程
條件滿足: 通知阻塞的線程開始工作
(3) 條件變量的類型:
pthread_cond_t cond;
(4) 主要函數:
初始化一個條件變量
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
第二參數一般為NULL
銷毀一個條件變量
int pthread_cond_destroy(pthread_cond_t *cond);
阻塞等待一個條件變量
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
阻塞線程
將已經上鎖的mutex解鎖
解除阻塞后會對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);
(5) 練習: 生產者和消費者模型
也能同步, 消費者消費完產品之后, 因為條件變量會阻塞, 之后不會再去消費,
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>
// 節點結構
typedef struct node {
int data;
struct node* next;
}Node;
// 永遠指向鏈表頭部的指針
Node *head = NULL;
// 線程同步 --> 互斥鎖
pthread_mutex_t mutex;
// 阻塞線程 --> 條件變量類型的變量
pthread_cond_t cond;
// 生產者
void *producer(void *arg) {
while (1) {
// 創建一個鏈表的節點
Node *pnew = (Node*)malloc(sizeof(Node));
// 節點初始化
pnew->data = rand() % 1000; // 0-999
// 使用互斥鎖保護共享數據
pthread_mutex_lock(&mutex);
pnew->next = head;
head = pnew;
printf("======> producer: %lu, %d\n", pthread_self(), pnew->data);
pthread_mutex_unlock(&mutex);
// 通知阻塞的消費者線程, 解除阻塞
pthread_cond_signal(&cond);
sleep(rand() % 3);
}
return NULL;
}
void *customer(void *arg) {
while (1) {
pthread_mutex_lock(&mutex);
// 判斷鏈表是否為空
if (head == NULL) {
//continue;
// 線程阻塞
// 該函數會對互斥鎖解鎖
pthread_cond_wait(&cond, &mutex);
// 解除阻塞之后, 對互斥鎖做加鎖操作
}
// 鏈表不為空, 刪除頭節點
Node *pdel = head;
head = head->next;
printf("------> customer: %lu, %d\n", pthread_self(), pdel->data);
free(pdel);
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main(int argc, const char *argv[]) {
pthread_t p1, p2;
// init
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
// 創建生產者線程
pthread_create(&p1, NULL, producer, NULL);
// 創建消費者線程
pthread_create(&p2, NULL, customer, NULL);
// 阻塞回收子線程
pthread_join(p1, NULL);
pthread_join(p2, NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}