zoukankan      html  css  js  c++  java
  • 条件变量

    (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
    ", 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
    ", 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;
    }
    
  • 相关阅读:
    阿里巴巴图标库在项目中的用法
    js对象的深拷贝
    Ajax
    HTML5新增的canvas是什么--通过刮奖效果学习
    一些最基础的面试题
    微信小程序实现列表搜索功能
    vue的基础双向绑定
    ES6 Promise 的不完全实现
    JQ学习
    播放音乐进度条
  • 原文地址:https://www.cnblogs.com/hesper/p/10738996.html
Copyright © 2011-2022 走看看