条件变量:

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

主要应用函数:

    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
<stdio.h>

#include
<pthread.h>

#include
<stdlib.h>

#include
<unistd.h>

 

typedef
struct
my_pth

{

    struct
my_pth *next;

    int num;

}my_pth;

 

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

pthread_cond_t my_produc = PTHREAD_COND_INITIALIZER;

my_pth *head;

 

void * produc(void *p)

{

    my_pth *temp = NULL;

    int num = (int)p;

 

    while (1)

    {

        temp = (my_pth*)malloc(sizeof(my_pth));//生产

 

        pthread_mutex_lock(&mutex);//加锁

 

        temp->num = rand() % 50;

        temp->next = head;

        head = temp;

        //这里在运行5次之后会得到一个有5个元素的链表,只不过,链表的元素是从后往前加的,即:最开始的元素在最后面。

        

        printf("++++++++++++++++++++++++++++++++++++++++++++num=%d.我是%d号线程\n", temp->num, num);

        pthread_mutex_unlock(&mutex);//解锁

        pthread_cond_signal(&my_produc);//唤醒其他线程

 

        sleep(1);

    }

    return
NULL;

}

 

void *consumers(void *p)

{

    my_pth *temp = NULL;

    int num = (int)p;

 

    while (1)

    {

        pthread_mutex_lock(&mutex);//pthread_cond_wait要解锁,这里自然要加锁

        while (head == NULL)

        {

            pthread_cond_wait(&my_produc, &mutex);//该函数解锁mutex,然后阻塞本线程,被唤醒后加锁mutex;

        }

        temp = head;

        printf("------------num=%d.我是%d号线程\n", temp->num, num);

        head = head->next;

        free(temp);//消耗

        pthread_mutex_unlock(&mutex);//解锁

        sleep(1);

    }

    return
NULL;

}

 

int main(void)

{

    pthread_t pth[10];

    for (int i = 0; i != 5; i++)

    {

        pthread_create(&pth[i], NULL, produc, (void*)i);

    }

    for (int i = 0; i != 5; i++)

    {

        pthread_create(&pth[i + 5], NULL, consumers, (void*)i);

    }

    sleep(3);

    for (int i = 0; i != 10; i++)

    {

        pthread_cancel(pth[i]);

        pthread_join(pth[i], NULL);

    }

    pthread_mutex_destroy(&mutex);

    pthread_cond_destroy(&my_produc);

 

    return 0;

}

编译后运行:,因为直接输出到屏幕会浪费造成错乱,原因我在《一秒钟你的电脑上能数多少数》中说明了的,所以我将其输入到文件中。观察结果会发现写和读时对应的,基本上呈现一种对称关系。这取决于链表的生成顺序。这里要注意的是,因为在主线程中是先生成生产者的,生产者中是有互斥量对线程加解锁的,这就保证了链表的生成是不会错乱的。这个在结果中也是体现了的。要注意的是:链表是最开始的元素在最后。所以才有这样的读顺序。

现在我们将生产者的数目减少位3个,看看结果如何:。惊不惊喜,意不意外?先不说阻塞的事儿,先看看结果,我这次没有输出到文件中,还好没输出到文件中,不然我都不知道怎么回事。还是挺好的,没有抢食的情况,生产一个菜消费一个,有序,不乱。虽然3号4号消费者机会相对少一些。所以总的来说还是好的,就是为嘛3秒后没有主动结束程序啊?不是在主线程中调用了pthread_cancel函数么?为嘛没杀死?简单一分析我们就能够知道,这玩意肯定是生产者先死了,消费者发现head==NULL才阻塞在那里。毕竟当生产者消费者数量一样的时候没出现这样的情况。但是我有怕pthread_cancel函数啊。其实原因也简单,就是因为它阻塞在那里了。没有进入内核,没有系统调发生。所以怕pthread_cancel没杀死。然后线程又一直阻塞在那里,等待被唤醒。这就像pause函数没有接收到alarm函数的信号一样。一直被阻塞。最后只能强制杀死,说到这里,我们能不能用kill函数杀死线程?不知道,一个是线程,一个是进程,不知道,留着等以后填坑。

条件变量的优点:

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

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

Linux:条件变量的更多相关文章

  1. 理解 Linux 条件变量

    理解 Linux 条件变量 1 简介 当多个线程之间因为存在某种依赖关系,导致只有当某个条件存在时,才可以执行某个线程,此时条件变量(pthread_cond_t)可以派上用场.比如: 例1: 当系统 ...

  2. linux 条件变量与线程池

    条件变量Condition Variables 概述 1. 条件变量提供了另外一种线程同步的方式.如果没有条件变量,程序需要使用线程连续轮询(可能在临界区critical section内)方式检查条 ...

  3. linux 条件变量

    互斥量就是一把锁,在访问数据时能保证同一时间内只有一个线程访问数据,在访问完以后再释放互斥量上的锁. 条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条 ...

  4. linux条件变量

    条件变量用于线程之间的通信,和互斥锁一起使用.条件变量用于及时通知等待的线程条件的变化,使线程不至于错过变化. 考虑下面的情况,有AB两个线程对index这个全局变量进行++,一个线程C用于判断,in ...

  5. linux条件变量使用和与信号量的区别

    近来在项目中用到条件变量和信号量做同步时,这一块一直都有了解,但也一直没有总结,这次总结一下,给大家提供点参考,也给自己留点纪念. 首先,关于信号量和条件变量的概念可以自行查看APUE,我这直接把AP ...

  6. Linux 条件变量函数signal和wait补充

    pthread_cond_wait必须放在pthread_mutex_lock和pthread_mutex_unlock之间,因为他要根据共享变量的状态来觉得是否要等待,而为了不永远等待下去所以必须要 ...

  7. 转载~kxcfzyk:Linux C语言多线程库Pthread中条件变量的的正确用法逐步详解

    Linux C语言多线程库Pthread中条件变量的的正确用法逐步详解   多线程c语言linuxsemaphore条件变量 (本文的读者定位是了解Pthread常用多线程API和Pthread互斥锁 ...

  8. [转]一个简单的Linux多线程例子 带你洞悉互斥量 信号量 条件变量编程

    一个简单的Linux多线程例子 带你洞悉互斥量 信号量 条件变量编程 希望此文能给初学多线程编程的朋友带来帮助,也希望牛人多多指出错误. 另外感谢以下链接的作者给予,给我的学习带来了很大帮助 http ...

  9. linux多线程-互斥&条件变量与同步

    多线程代码问题描述 我们都知道,进程是操作系统对运行程序资源分配的基本单位,而线程是程序逻辑,调用的基本单位.在多线程的程序中,多个线程共享临界区资源,那么就会有问题: 比如 #include < ...

  10. linux多线程同步pthread_cond_XXX条件变量的理解

    在linux多线程编程中,线程的执行顺序是不可预知的,但是有时候由于某些需求,需要多个线程在启动时按照一定的顺序执行,虽然可以使用一些比较简陋的做法,例如:如果有3个线程 ABC,要求执行顺序是A-- ...

随机推荐

  1. [UE4]UMG编辑器:控件作为变量、预设锚点和自由锚点

  2. 虚拟机挂载光盘,同时修改yum源为光盘挂载目录

    VMware下挂载光盘并安装文件https://blog.csdn.net/gfd54gd5f46/article/details/53968293 linux修改yum本地源的方法https://w ...

  3. Making a view in a listview invisible android

    问题: I have a ListView that's using a custom adapter. I want to dynamically add/remove items from the ...

  4. UE4中使用URL图片

    转自:http://www.52vr.com/article-911-1.html

  5. MySQL设置远程连接

    Window下MySQL设置开启远程连接mysql数据库 1.新建用户远程连接mysql数据库grant all on *.* to admin@'%' identified by '123456' ...

  6. XrmToolBox 连接

  7. python-day02-购物车

    购物车 需求: 1.启动程序后,让用户输入工资,然后打印商品列表: 2.容许用户根据商品编号购买商品: 3.用户选择商品后,检测余额是否足够,够了就直接扣款,不够就提醒客户: 4.随时可以退出,退出时 ...

  8. String,StringBuilder,StringBuffer三者的区别(Java)

    这三个类之间的区别主要是在两个方面,即运行速度和线程安全这两方面. 1. 首先说运行速度,或者说是执行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer &g ...

  9. django连接mysql数据库以及建表操作

    django连接mysql数据库需要在project同名的目录下面的__init__.py里面加入下面的东西 import pymysql pymysql.install_as_MySQLdb() 找 ...

  10. IntelliJ Idea设置Could not autowire. No beans of 'xxx' type found

    1.问题描述 在Idea的spring工程里,经常会遇到Could not autowire. No beans of ‘xxxx’ type found的错误提示.但程序的编译和运行都是没有问题的, ...