linux线程同步(2)-条件变量

https://www.cnblogs.com/yuuyuu/p/5140875.html

linux线程同步(2)-条件变量

一.概述                                                   

上一篇,介绍了互斥量。条件变量与互斥量不同,互斥量是防止多线程同时访问共享的互斥变量来保护临界区。条件变量是多线程间可以通过它来告知其他线程某个状态发生了改变,让等待在这个条件变量的线程继续执行。通俗一点来讲:设置一个条件变量让线程1等待在一个临界区的前面,当其他线程给这个变量执行通知操作时,线程1才会被唤醒,继续向下执行。

条件变量总是和互斥量一起使用,互斥量保护着条件变量,防止多个线程对条件变量产生竞争。等会写个小例子,看它们如何一起合作!

二.函数接口                                            

1.初始化条件变量

1.1:宏常量初始化

1 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

1.2:函数初始化

1 #include <pthread.h>
2 
3 int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);

跟互斥量类似,cond是条件变量的结构指针,attr是条件变量属性的结构指针。

2.等待和通知条件变量

复制代码
1 #include <pthread.h>
2 
3 int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
4 int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
5 
6 int pthread_cond_broadcast(pthread_cond_t *cond);
7 int pthread_cond_signal(pthread_cond_t *cond);
复制代码

等待函数里面,要传入一个互斥量。pthread_cond_timewait()可以指定一个时间来等待,如果规定的时间没有获得通知,就返回ETIMEDOUT错误。而pthread_cond_wait()会一直阻塞

通知函数,pthread_cond_signal()至少唤醒一个等待的线程,pthread_cond_broadcast()会唤醒在该条件变量上所有线程。

3.销毁条件变量

1 #include <pthread.h>
2 
3 int pthread_cond_destroy(pthread_cond_t *cond);

三.简单的例子                                       

我们还是用上一篇互斥量的例子。单独使用互斥量时,有些线程要获取某个状态的成立,需要多次进出临界区,对互斥量频繁加锁解锁造成系统资源的浪费。下面结合条件变量来解决这个问题:

复制代码
  1 /**
  2  * @file pthread_mutex.c
  3  */
  4 
  5 #include <stdio.h>
  6 #include <stdlib.h>
  7 #include <string.h>
  8 #include <unistd.h>
  9 #include <pthread.h>
 10 
 11 /* 定义互斥量 */
 12 pthread_mutex_t mtx;
 13 /* 互斥量属性 */
 14 pthread_mutexattr_t mtx_attr;
 15 /* 全局资源 */
 16 int money;
 17 
 18 /* 条件变量 */
 19 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
 20 
 21 void err_exit(const char *err_msg)
 22 {
 23     printf("error:%s\n", err_msg);
 24     exit(1);
 25 }
 26 
 27 /* 线程函数 */
 28 void *thread_fun(void *arg)
 29 {
 30     while (1)
 31     {
 32         /* 加锁 */
 33         pthread_mutex_lock(&mtx);
 34 
 35         /* 条件变量 */
 36         while (money > 0)
 37         {
 38             printf("子线程坐等money等于0...\n");
 39             pthread_cond_wait(&cond, &mtx);
 40         }
 41 
 42         printf("子线程进入临界区查看money\n");
 43         if (money == 0)
 44         {
 45             money += 200;
 46             printf("子线程:money = %d\n", money);
 47         }
 48 
 49         /* 解锁 */
 50         pthread_mutex_unlock(&mtx);
 51 
 52         sleep(1);
 53     }
 54 
 55     return NULL;
 56 }
 57 
 58 int main(void)
 59 {
 60     pthread_t tid;
 61 
 62     /* 初始化互斥量属性 */
 63     if (pthread_mutexattr_init(&mtx_attr) == -1)
 64         err_exit("pthread_mutexattr_init()");
 65 
 66     /* 设置互斥量属性 */
 67     if (pthread_mutexattr_settype(&mtx_attr, PTHREAD_MUTEX_NORMAL) == -1)
 68         err_exit("pthread_mutexattr_settype()");
 69 
 70     /* 初始化互斥量 */
 71     if (pthread_mutex_init(&mtx, &mtx_attr) == -1)
 72         err_exit("pthread_mutex_init()");
 73 
 74     /* 创建一个线程 */
 75     if (pthread_create(&tid, NULL, thread_fun, NULL)== -1)
 76         err_exit("pthread_create()");
 77 
 78     money = 1000;
 79     while (1)
 80     {
 81         /* 加锁 */
 82         pthread_mutex_lock(&mtx);
 83 
 84         if (money > 0)
 85         {
 86             money -= 100;
 87             printf("主线程:money = %d\n", money);
 88         }
 89 
 90         /* 解锁 */
 91         pthread_mutex_unlock(&mtx);
 92 
 93         /* 如果money = 1,就通知子线程 */
 94         if (money == 0)
 95         {
 96             printf("通知子线程\n");
 97             pthread_cond_signal(&cond);
 98         }
 99 
100         sleep(1);
101     }
102 
103     return 0;
104 }
复制代码

代码跟上一个例子几乎一样,就加了一个条件变量。编译运行:

可以看到第39行的等待条件变量触发后,子线程会一直等待,直到主线程通知它。这样子线程就不会频繁进入临界区,频繁加锁解锁。

四.深入知识                                             

1.等待函数里面要传入一个互斥量,这个互斥量会在这个函数调用时会发生如下变化:函数刚刚被调用时,会把这个互斥量解锁,然后让调用线程阻塞,解锁后其他线程才有机会获得这个锁。当某个线程调用通知函数时,这个函数收到通知后,又把互斥量加锁,然后继续向下操作临界区。可见这个设计是非常合理的!!!

2.条件变量的等待函数用while循环包围,本程序的第36行。原因:如果有多个线程都在等待这个条件变量关联的互斥量,当条件变量收到通知,它下一步就是要锁住这个互斥量,但在这个极小的时间差里面,其他线程抢先获取了这互斥量并进入临界区把某个状态改变了。此时这个条件变量应该继续判断别人刚刚抢先修改的状态,即继续执行while的判断。还有一个原因时防止虚假通知,收到虚假通知后,只要while里面的条件为真,就继续休眠!!!


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

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

相关文章

UVa227

【题目描述】 传送门 【题目分析】 题目的意思很简单&#xff0c;只是输入输出很毒瘤&#xff0c;我一开始用的fgets然后用scanf(" ")吃掉所有的空格和换行&#xff0c;可是这样有可能将迷宫的空格吃掉&#xff08;例如这个空格恰好在第一行第一列&#xff09;。 …

点对点数据链路层

数据链路层的主要功能将数据转换为相应的比特流使用的信道主要有点对点的信道方式(一对一的方式), 以及广播的信道方式 一. 点对点信道的数据链路层 1. 数据链路和数据帧 链路就是从一个结点连接到相邻结点的一段物理线路(有线或者无线), 期间不准有任何的交换结点, 因此两台…

UVa232

[题目描述] 传送门 [题目分析] 简单的模拟,注意细节 [AC代码] #include<cstdio> #include<cstring> #include<algorithm> #include<climits> #include<cctype> #include<queue> #include<set>using namespace std;typedef long…

linux线程同步(1)-互斥量

http://www.cnblogs.com/yuuyuu/p/5140251.html 一.概述 互斥量是线程同步的一种机制&#xff0c;用来保护多线程的共享资源。同一时刻&#xff0c;只允许一个线程对临界区进行访问。 互斥量的工作流程&#xff1a;创建一个…

UVa1368

[题目描述] 传送门 [题目分析] 乍一看好像有点复杂,稍微思考一下只需要找到每个位置中最多的碱基.如果相等的话优先输出字典序小的. [AC代码] #include<cstdio> #include<cstring> #include<algorithm> #include<climits> #include<cctype>…

linux线程同步(3)-读写锁

http://www.cnblogs.com/yuuyuu/p/5143881.html 一.概述 读写锁与互斥量的功能类似&#xff0c;对临界区的共享资源进行保护&#xff01;互斥量一次只让一个线程进入临界区&#xff0c;读写锁比它有更高的并行性。读写锁有…

树的相关笔试面试题

1. 树的创建 已知一个先序遍历数的结果用数组表示, 其中空节点用 null_node 表示, 要求创建出这棵树. 同样采用递归的思想, 先定义一个指针, 指向数组中的第一个元素, 然后给数组的第一个结点创建相应的结点, 然后指针后移, 递归创建根节点的左子树, 递归创建根节点的右子树, …

UVa202

[题目描述] 传送门 [题目分析] 就是一个模拟,不过稍微有点小复杂,而且输出格式有点小毒瘤. 不过只是RE了两发,PE了一发就过了,还是很开心. 需要注意数组要开很大,可能循环节出现在很后. 每个输出样例应该输出一个空行,最后面也应该有,不然会PE [AC代码] #include<cst…

linux线程同步(5)-屏障

http://www.cnblogs.com/yuuyuu/p/5152560.html 一.概述 barrier(屏障)与互斥量&#xff0c;读写锁&#xff0c;自旋锁不同&#xff0c;它不是用来保护临界区的。相反&#xff0c;它跟条件变量一样&#xff0c;是用来协同多…

浅谈软件测试

一. 什么是软件测试 软件测试是一个过程或者一系列过程, 用来测试计算机代码完成了其应该完成的功能, 不执行不该有的操作.或者说软件测试是根据软件开发各阶段的功能和说明而精心设计的一批测试用例, 并根据测试用例运行程序, 以发现程序错误的过程. 二. 软件测试的心理学和…

UVa10340

【题目描述】 传送门 【题目分析】 求字串&#xff0c;最好还是处理母串&#xff0c;每次找到一个子串就加1&#xff0c;这样处理不用处理细节 【AC代码】 #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include&l…

浅析linux下的条件变量

一.条件变量 条件变量是用来等待线程而不是上锁的&#xff0c;条件变量通常和互斥锁一起使用。条件变量之所以要和互斥锁一起使用&#xff0c;主要是因为互斥锁的一个明显的特点就是它只有两种状态&#xff1a;锁定和非锁定&#xff0c;而条件变量可以通过允许线程阻塞和等待另…

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…