條件變量


(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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM