条件变量

(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;
}
posted @ 2019-04-19 21:39  张飘扬  阅读(2017)  评论(0编辑  收藏  举报