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

    条件变量:

           条件变量本身不是锁!但它也可以造成线程阻塞。通常与互斥锁配合使用。给多线程提供一个会合的场所。

    主要应用函数:

           pthread_cond_init函数

           pthread_cond_destroy函数

           pthread_cond_wait函数

           pthread_cond_timedwait函数

           pthread_cond_signal函数

           pthread_cond_broadcast函数

    以上6 个函数的返回值都是:成功返回0, 失败直接返回错误号。

           pthread_cond_t类型   用于定义条件变量

           pthread_cond_t cond;

    pthread_cond_init函数

    初始化一个条件变量

    int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);      

    参2:attr表条件变量属性,通常为默认值,传NULL即可

    也可以使用静态初始化的方法,初始化条件变量:

    pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

    pthread_cond_destroy函数

    销毁一个条件变量

    int pthread_cond_destroy(pthread_cond_t *cond);

    pthread_cond_wait函数

    阻塞等待一个条件变量

        int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);

    函数作用:

    1. 阻塞等待条件变量cond(参1)满足
    2. 释放已掌握的互斥锁(解锁互斥量)相当于pthread_mutex_unlock(&mutex);

     1.2.两步为一个原子操作。

    1. 当被唤醒,pthread_cond_wait函数返回时,解除阻塞并重新申请获取互斥锁pthread_mutex_lock(&mutex);

    pthread_cond_timedwait函数

    限时等待一个条件变量

    int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);

           参3:    参看man sem_timedwait函数,查看struct timespec结构体。

                  struct timespec {

                         time_t tv_sec;        /* seconds */ 秒

                         long   tv_nsec;    /* nanosecondes*/ 纳秒

                  }                                                      

    形参abstime:绝对时间。                                                               

    如:time(NULL)返回的就是绝对时间。而alarm(1)是相对时间,相对当前时间定时1秒钟。

                         struct timespec t = {1, 0};

                         pthread_cond_timedwait (&cond, &mutex, &t); 只能定时到 1970年1月1日 00:00:01秒(早已经过去)

                  正确用法:

                         time_t cur = time(NULL); 获取当前时间。

    struct timespec t;  定义timespec 结构体变量t

                         t.tv_sec = cur+1; 定时1秒

    pthread_cond_timedwait (&cond, &mutex, &t); 传参                          参APUE.11.6线程同步条件变量小节

                  在讲解setitimer函数时我们还提到另外一种时间类型:

            struct timeval {

                 time_t      tv_sec;  /* seconds */ 秒

                 suseconds_t tv_usec; /* microseconds */ 微秒

            };

    pthread_cond_signal函数

    唤醒至少一个阻塞在条件变量上的线程

    int pthread_cond_signal(pthread_cond_t *cond);

    pthread_cond_broadcast函数

    唤醒全部阻塞在条件变量上的线程

        int pthread_cond_broadcast(pthread_cond_t *cond);

    生产者消费者条件变量模型

    线程同步典型的案例即为生产者消费者模型,而借助条件变量来实现这一模型,是比较常见的一种方法。假定有两个线程,一个模拟生产者行为,一个模拟消费者行为。两个线程同时操作一个共享资源(一般称之为汇聚),生产向其中添加产品,消费者从中消费掉产品。

    看如下示例,使用条件变量模拟生产者、消费者问题:

    #include <stdlib.h>
    #include <unistd.h>
    #include <pthread.h>
    
    struct msg {
        struct msg *next;
        int num;
    };
    struct msg *head;
    
    pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
    
    void *consumer(void *p)
    {
        struct msg *mp;
        for (;;) {
            pthread_mutex_lock(&lock);
            while (head == NULL) {           //头指针为空,说明没有节点    可以为if吗
                pthread_cond_wait(&has_product, &lock);
            }
            mp = head;      
            head = mp->next;                //模拟消费掉一个产品
            pthread_mutex_unlock(&lock);
    
            printf("-Consume ---%d
    ", mp->num);
            free(mp);
            sleep(rand() % 5);
        }
    }
    void *producer(void *p)
    {
        struct msg *mp;
        while (1) {
            mp = malloc(sizeof(struct msg));
            mp->num = rand() % 1000 + 1;        //模拟生产一个产品
            printf("-Produce ---%d
    ", mp->num);
    
            pthread_mutex_lock(&lock);
            mp->next = head;
            head = mp;
            pthread_mutex_unlock(&lock);
    
            pthread_cond_signal(&has_product);  //将等待在该条件变量上的一个线程唤醒
            sleep(rand() % 5);
        }
    }
    int main(int argc, char *argv[])
    {
        pthread_t pid, cid;
        srand(time(NULL));
    
        pthread_create(&pid, NULL, producer, NULL);
        pthread_create(&cid, NULL, consumer, NULL);
    
        pthread_join(pid, NULL);
        pthread_join(cid, NULL);
        return 0;
    }

    运行结果:

    ubuntu1604@ubuntu:~/wangqinghe/linux/20190820$ ./conditionVar_product_consumer

    -Produce ---276

    -Consume ---276

    -Produce ---514

    -Consume ---514

    -Produce ---889

    -Consume ---889

    ^C

    条件变量的优点:

           相较于mutex而言,条件变量可以减少竞争。

    如直接使用mutex,除了生产者、消费者之间要竞争互斥量以外,消费者之间也需要竞争互斥量,但如果汇聚(链表)中没有数据,消费者之间竞争互斥锁是无意义的。有了条件变量机制以后,只有生产者完成生产,才会引起消费者之间的竞争。提高了程序效率。

    /***
    condition.c
    ***/
    #include<stdio.h>
    #include<unistd.h>
    #include<pthread.h>
    #include<stdlib.h>
    
    struct msg
    {
        struct msg *next;
        int num;
    };
    
    struct msg *head;
    struct msg *mp;
    
    pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
    
    void *consumer(void *p)
    {
        for(;;)
        {
            pthread_mutex_lock(&lock);
            while(head == NULL)
            {
                pthread_cond_wait(&has_product,&lock);
            }
            mp = head;
            head = mp->next;
            pthread_mutex_unlock(&lock);
    
            printf("-Consumer ---%d
    ",mp->num);
            free(mp);
            mp = NULL;
            sleep(rand() % 5);
        }
    }
    
    void *producer(void *p)
    {
        for(;;)
        {
            mp = malloc(sizeof(struct msg));
            mp->num = rand() %1000 + 1;
            printf("-Producer ---%d
    ",mp->num);
            pthread_cond_signal(&has_product);
            sleep(rand() % 5);
        }
    }
    
    int main()
    {
        pthread_t pid,cid;
        srand(time(NULL));
    
        pthread_create(&pid,NULL,producer,NULL);
        pthread_create(&cid,NULL,consumer,NULL);
    
        pthread_join(pid,NULL);
        pthread_join(cid,NULL);
    
        return 0;
    }

    运行结果:

    ubuntu1604@ubuntu:~/wangqinghe/linux/20190820$ ./condition

    -Producer ---431

    -Producer ---160

    -Producer ---719

    -Producer ---240

    -Producer ---304

    -Producer ---408

    -Producer ---946

    -Producer ---619

    -Producer ---412

    -Producer ---997

    -Producer ---489

    -Producer ---295

    ^C

  • 相关阅读:
    如何通过命令行窗口查看sqlite数据库文件
    eclipse自动补全的设置
    文本装饰
    注释和特殊符号
    文本装饰
    网页背景
    通过ArcGIS Server admin 查看和删除已注册的 Web Adaptor
    通过 ArcGIS Server Manager 查看已安装的 Web Adaptor
    通过 ArcGIS Server Manager 验证 DataStore
    Windows上安装ArcGIS Enterprise——以 Windows Server 2012 R2上安装 ArcGIS 10.8为例
  • 原文地址:https://www.cnblogs.com/wanghao-boke/p/11389840.html
Copyright © 2011-2022 走看看