浅析linux下的条件变量

  一.条件变量

    条件变量是用来等待线程而不是上锁的,条件变量通常和互斥锁一起使用。条件变量之所以要和互斥锁一起使用,主要是因为互斥锁的一个明显的特点就是它只有两种状态:锁定和非锁定,而条件变量可以通过允许线程阻塞和等待另一个线程发送信号来弥补互斥锁的不足,所以互斥锁和条件变量通常一起使用

    当条件满足的时候,线程通常解锁并等待该条件发生变化,一旦另一个线程修改了环境变量,就会通知相应的环境变量唤醒一个或者多个被这个条件变量阻塞的线程。这些被唤醒的线程将重新上锁,并测试条件是否满足。一般来说条件变量被用于线程间的同步;当条件不满足的时候,允许其中的一个执行流挂起和等待。

条件变量中常用的API:

     1).条件变量类型为:pthread_cond_t ,类似互斥变量,条件变量的初始化有两种方式:

      静态:pthread_cond_t mycon=PTHREAD_COND_INITIALIZER;

      动态:通过调用pthread_cond_init函数,函数原型为:

[cpp] view plain copy
  1. 静态:pthread_cond_t mycon=PTHREAD_COND_INITIALIZER;  

     cond:环境变量.

     attr:条件变量属性.

     成功返回0,失败返回错误码.

     2).条件变量摧毁函数:pthread_cond_destroy(&mycond);

[cpp] view plain copy
  1. int pthread_cond_destroy(pthread_cond_t *cond);  

     成功返回0,失败返回错误码.

     摧毁所指定的条件变量,同时将会释放所给它分配的资源。调用该函数的进程也并不等待在参数所指定的条件变量上。

     3).条件变量等待函数。pthread_cond_wait(&mycond,&mylock);

     

[cpp] view plain copy
  1. int pthread_cond_timedwait(pthread_cond_t *restrict cond,  
  2.            pthread_mutex_t *restrict mutex,  
  3.            const struct timespec *restrict abstime);  
  4.     int pthread_cond_wait(pthread_cond_t *restrict cond,  
  5.            pthread_mutex_t *restrict mutex);  

    cond:条件变量

    mutex:互斥锁

 pthread_cond_wait和pthread_cond_timedwait的区别:

    pthread_cond_timedwait函数类型与函数pthread_cond_wait,区别在于,如果达到或是超过所引用的参数*abstime,它将结束并返回错误ETIME.

    timespec

[cpp] view plain copy
  1. typedef struct timespec  
  2.    {  
  3.       time_t     tv_sec;    //!> 秒  
  4.       long     tv_nsex;    //!> 毫秒  
  5.    }timespec_t;  

    当时间超过之前预设定的时会返回错误.

    4).条件变量通知函数:pthread_cond_signal和pthread_cond_broadcast

[cpp] view plain copy
  1. int pthread_cond_broadcast(pthread_cond_t *cond);  
  2. int pthread_cond_signal(pthread_cond_t *cond);  

pthread_cond_signal和pthread_cond_broadcast的区别:

       pthread_cond_signal:只唤醒一个在相同条件变量中阻塞的线程将会被唤醒

       pthread_cond_broadcast:唤醒等待队列中的所有线程

二.一个关于互斥锁和条件变量的栗子

   栗子:用互斥锁和条件变量的概念实现一个简单的生产者和消费者的模型。

 生产者和消费者模型:

    1).满足互斥与同步条件,用互斥锁和条件变量实现

    2).多个生产者和消费者:生产者和生产者属于互斥关系;生产者和消费者属于互斥和同步关系;消费者和消费者属于竞争关系,需要互斥锁

    3).生产者和消费者模型中存在如下几种关系和角色:3种关系,2种角色,1种交换媒介(一般是一段内存)

    下例以单生产者和单消费者,交换媒介为链表实现的生产者消费者模型

     

[cpp] view plain copy
  1. procon.c  
  2.   
  3. #include<stdio.h>  
  4. #include<stdlib.h>  
  5. #include<assert.h>  
  6. #include<pthread.h>  
  7.   
  8. typedef struct LinkNode  
  9. {  
  10.     int data;  
  11.     struct LinkNode *next;  
  12. }Node;  
  13.   
  14. pthread_mutex_t mylock=PTHREAD_MUTEX_INITIALIZER;  
  15. pthread_cond_t mycond=PTHREAD_COND_INITIALIZER;  
  16.   
  17. Node *CreatNode(int data)  
  18. {  
  19.     Node *NewNode=(Node *)malloc(sizeof(Node));  
  20.     if(NULL == NewNode)  
  21.     {  
  22.         perror("malloc");  
  23.         return NULL;  
  24.     }  
  25.     NewNode->data=data;  
  26.     NewNode->next=NULL;  
  27.     return NewNode;  
  28. }  
  29.   
  30. void InitLink(Node **head)  
  31. {  
  32.     *head=CreatNode(0);  
  33. }  
  34.   
  35. int IsEmpty(Node *head)  
  36. {  
  37.     assert(head);  
  38.     if(head->next)  
  39.         return 0;    //not empty  
  40.     else  
  41.         return 1;    //empty  
  42. }  
  43.   
  44. void PushFront(Node *head,int data)  
  45. {  
  46.     assert(head);  
  47.     Node *NewNode=CreatNode(data);  
  48.     NewNode->next=head->next;  
  49.     head->next=NewNode;  
  50. }  
  51.   
  52. void PopFront(Node *head,int *data)  
  53. {  
  54.     assert(data);  
  55.     assert(head);  
  56.     if(IsEmpty(head))  
  57.     {  
  58.         printf("empty link\n");  
  59.         return ;  
  60.     }  
  61.     Node *del=head->next;  
  62.     *data=del->data;  
  63.     head->next=del->next;  
  64.     free(del);  
  65.     del=NULL;  
  66. }  
  67.   
  68. void DisplayLink(Node *head)  
  69. {  
  70.     assert(head);  
  71.     Node *cur=head->next;  
  72.     while(cur)  
  73.     {  
  74.         printf("%d ",cur->data);  
  75.         cur=cur->next;  
  76.     }  
  77.     printf("\n");  
  78. }  
  79.   
  80. void DestroyLink(Node *head)  
  81. {  
  82.     int data=0;  
  83.     assert(head);  
  84.     while(!IsEmpty(head))  
  85.     {  
  86.         PopFront(head,&data);  
  87.     }  
  88.     free(head);  
  89. }  
  90.   
  91. void *product_run(void *arg)  
  92. {  
  93.     int data=0;  
  94.     Node *head=(Node *)arg;  
  95.     while(1)  
  96.     {  
  97.         usleep(100000);  
  98.         data=rand()%1000;  
  99.         pthread_mutex_lock(&mylock);  
  100.         PushFront(head,data);  
  101.         pthread_mutex_unlock(&mylock);  
  102.         pthread_cond_signal(&mycond);  
  103.         printf("product is done,data=%d\n",data);  
  104.     }  
  105. }  
  106.   
  107. void *consumer_run(void *arg)  
  108. {  
  109.     int data=0;  
  110.     Node *head=(Node *)arg;  
  111.     while(1)  
  112.     {  
  113.         pthread_mutex_lock(&mylock);  
  114.         while(IsEmpty(head))  
  115.         {  
  116.             pthread_cond_wait(&mycond,&mylock);  
  117.         }  
  118.         PopFront(head,&data);  
  119.         pthread_mutex_unlock(&mylock);  
  120.         printf("consumer is done,data=%d\n",data);  
  121.     }  
  122. }  
  123.   
  124. void testprocon()  
  125. {  
  126.     Node *head=NULL;  
  127.     InitLink(&head);  
  128.     pthread_t tid1;  
  129.     pthread_t tid2;  
  130.     pthread_create(&tid1,NULL,product_run,(void *)head);  
  131.     pthread_create(&tid2,NULL,consumer_run,(void *)head);  
  132.   
  133.     pthread_join(tid1,NULL);  
  134.     pthread_join(tid2,NULL);  
  135.     DestroyLink(head);  
  136.     pthread_mutex_destroy(&mylock);  
  137.     pthread_cond_destroy(&mycond);  
  138.   
  139. }  
  140. int main()  
  141. {  
  142.     testprocon();  
  143.     return 0;  
  144. }  
  145.   
  146. Makefile  
  147. procon:procon.c  
  148.     gcc -o $@ $^ -lpthread  
  149. .PHONY:clean  
  150. clean:  
  151.     rm -f procon  


    

总结:

   条件变量用在某个线程需要在某种条件才去保护它将要操作的临界区的情况下,从而避免了线程不断轮询检查该条件是否成立而降低效率的情况,这是实现了效率提高。

  希望对读者有帮助吧~~~~

    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384000.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UVa1587

【题目描述】 传送门 【题目分析】 刚开始想简单了&#xff0c;认为只要相对的面相等就可以了。然后发现三个不同方向的面的边应该有相等的关系&#xff0c;即如果两个面公用一条边&#xff0c;那么这两个面的另外两条边就是另一个面的两条边。而且这三个量里面肯定有一个最…

Linux多线程与同步

https://www.cnblogs.com/freedomabcd/p/7774743.html 典型的UNIX系统都支持一个进程创建多个线程(thread)。在Linux进程基础中提到&#xff0c;Linux以进程为单位组织操作&#xff0c;Linux中的线程也都基于进程。尽管实现方式有异于其它的UNIX系统&#xff0c;但Linux的多线程…

内存管理(二)

页面置换算法 当发生缺页中断的时候, 系统会在内存中选择一个页面将其换出内存, 而当换出内存的时候如果该页面的内容在内存中发生修改,则必须将该新数据重新写回到磁盘, 然后再将需要换进的数据覆盖掉原来的数据, 而当该数据在内存中没有被修改的时候, 此时就直接用需要换进的…

两个栈实现一个队列/两个队列实现一个栈

http://blog.csdn.net/sinat_30472685/article/details/70157227 1两个栈实现一个队列 1.原理分析&#xff1a; 队列的主要操作有两个&#xff1a;入队操作和出队操作&#xff0c;出队时从队头出&#xff0c;入队是从队尾插入&#xff0c;入队的操作和入栈的操作类似&#xff0…

UVa1588

【题目描述】 传送门 【题目分析】 刚开始想了一会没有想到什么很好的算法&#xff0c;看到了长度最多为100&#xff0c;就知道自己想的没有什么意义了&#xff0c;直接暴力&#xff0c;把每一种填法都试一下就知道了。适当剪枝一下&#xff08;一个简单的乐观函数&#xff…

转:C++中const、volatile、mutable的用法

const修饰普通变量和指针 const修饰变量&#xff0c;一般有两种写法&#xff1a; const TYPE value; TYPE const value; 这两种写法在本质上是一样的。它的含义是&#xff1a;const修饰的类型为TYPE的变量value是不可变的。对于一个非指针的类型TYPE&#xff0c;无论怎么写&…

数据链路

广播信道的数据链路层 局域网的优点 网络为一个单位所拥有, 地理范围和站点数有限 局域网具有广播特性, 可以从一个站点方便地访问到整个网络. 各个主机之间可以共享资源, 无论是局域网上的硬件资源还是局域网上的软件资源 便于系统的扩展换和演化, 各个设备之间的位置可灵…

UVa11809

【题目描述】 传送门 【题目分析】 终于把这道题做完了&#xff0c;之前一直连题意都看不懂。实在不行上网找了一下大佬的博客&#xff0c;看懂题意后自己写&#xff0c;发现读入很难处理&#xff0c;就又学习了一下大佬的读入方法&#xff0c;用的是C里面的sstream&#xf…

数据链路层:基本概念

数据链路层的定义 对数据链路层有对上的网络层接口. 对下提供物理层的接口. 定义合适的传输差错率 对传输流进行管理, 以免快速的传输的数据被淹没. 比如发送端发送信号太快, 接受方接受速度较慢, 此时数据链路层就需要提供一定的功能解决这个问题 物理层上传输的基本单元是…

C++的沉迷与爱恋

每年的 09/28 於我都是一个特殊的日子 -- 不只是因为教师节。今年很特殊地没有普天同庆&#xff0c;那麽我就写篇文章自己庆祝一下好了。我於今年七月发表了一本着作《多型与虚拟》和一本译作《深度探索C物件模型》&#xff0c;获得很大的回响。这些作品都不是针对 C 的完全初学…

Insertion Sort——打表找规律

【题目描述】 Insertion sort is a simple sorting algorithm that builds the final sorted array one item at an iteration.More precisely, insertion sort iterates, consuming one input element each repetition, and growing a sorted output list. At each iteration…

数据链路层: 可靠性传输 六个协议

可靠性传输 1. 差错控制 发送方将数据帧发送, 但是当发送方发送的是一个 1的时候此时接受方却接受的是一个 0. (1)校验 接收方如果帧校验接受到的帧没有问题, 则对发送方发送一个肯定性的确认, 当对这个数据帧进行校验发现这个帧有问题的时候, 此时接受方一种是将这个数据帧…

c语言实现配置文件的读写

配置文件的格式如下&#xff1a; key1 value1 key2 value2 . . . 名值对以一个链接&#xff0c;一条记录以换行符分割 头文件&#xff1a; #include<stdio.h> #include<stdlib.h> #include <string.h> 函数原型&#xff1a; void trim(char *strIn, char *…

Educational Codeforces Round 73 (Rated for Div. 2)

A 很简单的一个模拟&#xff0c;只要前面的数字有两个以上就能合成后面的&#xff0c;我们进行一遍合成看能不能出现2048就可以了。 #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<iostream> #include&…

数据链路层: HDLC

一. 协议机 发送方和接收方. 同时有限状态机把协议形式化为一个四元组 (S,M,I,T), 其中你S表示进程和信道可能进入的集合, M 表示数据帧的状态, I 表示进程的初始状态, T 表示两两状态之间的转化. 每个系统状态可以分为发送状态, 接受状态和信道状态. 把状态用一个点进行表示,…

Miller_Rabin算法

为了测试一个大整数是不是素数&#xff0c;我们不能够使用传统的测试是否有因子的方法&#xff0c;因为那样的时间复杂度至少也是O(n)O(n)O(n)&#xff0c;空间复杂度是O(n)O(n)O(n)&#xff08;使用线性筛数法&#xff09;&#xff0c;时间复杂度还好说&#xff0c;空间复杂度…

bob-tong 字符串函数之Strtok()函数

https://www.cnblogs.com/Bob-tong/p/6610806.html Strtok()函数详解&#xff1a; 该函数包含在"string.h"头文件中 函数原型&#xff1a; char* strtok (char* str,constchar* delimiters ); 函数功能&#xff1a;   切割字符串&#xff0c;将str切分成一个个子…

数据链路层:SLIP(串型线路IP) PPP(点对点协议)

SLIP 没有差错控制, 传输时必须知道对方IP, 传输使用于低速业务 19.2k.应用非常受限 PPP协议 1. PPP协议功能 处理错误检测 支持多协议(IP, IPX, DECnet 等) 连接时允许协商 IP 地址 允许身份验证 2. PPP 的组成 串型链路上封装数据报, 即支持异步链路也支持面向 比特…

Honeycomb——BFS

【题目描述】 传送门 【题目分析】 看起来很复杂好像还要建图什么的&#xff0c;其实直接在原图上BFS就可以了&#xff0c;设置一下方向数组&#xff0c;然后直接跑就可以了。 【AC代码】 #include<cstdio> #include<cstring> #include<algorithm> #inc…

C语言中strspn()函数和strcspn()函数的对比使用

C语言strspn()函数&#xff1a;计算字符串str中连续有几个字符都属于字符串accept 头文件&#xff1a;#include <string.h> strspn() 函数用来计算字符串 str 中连续有几个字符都属于字符串 accept&#xff0c;其原型为&#xff1a; size_t strspn(const char *str, con…