条件变量:

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

主要应用函数:

    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. ARM Cortex-A9 (tiny 4412)

    要求 移植linux增加系统调用并烧写至开发板 详细步骤 一.搭建linux编译环境 1.GCC 编译器的安装: tar xzvf arm-linux-gcc-4.5.1-v6-vfp-2012030 ...

  2. 0001 - Spring MVC中的注解

    1.概述 Spring MVC框架提供了功能强大的注解,大大简化了代码开发的同时也提升了程序的可扩展性 2.注解 2.1.@RequestMapping Spring MVC通过@RequestMap ...

  3. C# 中使用锁防止多线程冲突

    在编程的时候经常会用到多线程,有时候如果多线程操作同一个资源就会导致冲突,.NET提供了多种方法来防止冲突发生,这里讲下Mutex 该类位于System.Threading命名空间,常用的方式是这样: ...

  4. OpenStack Nova虚拟机创建流程解析

    https://yikun.github.io/2017/09/27/OpenStack-Nova%E8%99%9A%E6%8B%9F%E6%9C%BA%E5%88%9B%E5%BB%BA%E6%B5 ...

  5. 使用Handlerf发送消息或使用Handler轮询时,报错IllegalStateException:This message is already in use.;

    java.lang.IllegalStateException: { when=-107ms what=9 obj=com.saicmaxus.maxuslife.model.CarInfo@be47 ...

  6. python hashillb 模块

    hashlib主要提供字符加密功能,将md5和sha模块整合到了一起,支持md5,sha1, sha224, sha256, sha384, sha512等算法 import hashlib # ## ...

  7. Linux free -m 详解命令

    如下显示free是显示的当前内存的使用,-m的意思是M字节来显示内容.我们来一起看看. 1 2 3 4 5 6 $ free -m                total       used    ...

  8. ORA-01940:无法删除当前已链接的用户(转)

    (1)查看用户的连接状况 select username,sid,serial# from v$session ------------------------------------------ 如 ...

  9. Strandbeest mechanism and Leg mechanism

    I have to say besides computer science study, I'm also interested in Leg mechanism. Share two keywor ...

  10. Geany 编辑器打开 高亮所选单词 功能

    Geany 编辑器打开 高亮所选单词 功能 在Ubuntu 系统的Software Center 工具中,搜索到geany, 下方有个 Miscellanous Plugins for Geany, ...