四十一、Linux 线程——线程同步之条件变量

41.1 概念

41.1.1 条件变量的介绍

  • 互斥锁的缺点是它只有两种状态:锁定和非锁定
  • 条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足
  • 条件变量内部是一个等待队列,放置等待的线程,线程在条件变量上等待和通知,互斥锁用来保护等待队列(对等待队列上锁),条件变量通常和互斥锁一起使用
  • 条件变量允许线程等待特定条件发生,当条件不满足时,线程通常先进入阻塞状态,等待条件发生变化。一旦其它的某个线程改变了条件,可唤醒一个或多个阻塞的线程
  • 具体的判断条件还需用户给出
  • 条件变量数据类型: pthread_cond_t

41.1.2 条件变量创建和销毁

1 #include <pthread.h>
2 int pthread_cond_init(pthread_cond_t *restrict cond, pthread_condattr_t *restrict attr);
3 int pthread_cond_destroy(pthread_cond_t *cond);
  • 函数参数:

    • cond:条件变量
    • attr:条件变量属性
  • 返回值:
    • 成功,返回 0;出错,返回错误编号

41.1.3 条件变量等待操作

1 #include <pthread.h>
2 int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
3 int pthread_cond_timewait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict timeout);
4
5 struct timespec {
6     time_t tv_sec;  /** seconds */
7     ong tv_nsec;    /** nanoseconds */
8 };
  • 函数参数:

    • cond:条件变量
    • mutex:互斥锁
  • 返回值:成功,返回 0,出错,返回错误编号
  • 互斥锁 mutex 是对条件变量 cond 的保护
  • 线程由于调用 wait 函数阻塞,否则释放互斥锁

41.1.4 条件变量通知操作

1 #include <pthread.h>
2 int pthread_cond_signal(pthread_cond_t *cond);
3 int pthread_cond_broadcast(pthread_cond_t *cond);
  • 函数参数:

    • cond:条件变量
  • 返回值:成功,返回 0;失败,返回错误编号
  • 当条件满足,线程需要通知等待的线程
  • pthread_cond_signal 函数通知单个线程
  • pthread_cond_broadcast 函数通知所有线程

41.1.5 pthread_cond_wait(cond, mutex) 函数内部流程

  1. unlock(&mutex):释放锁
  2. lock(&mutex)
  3. 将线程自己插入到条件变量的等待队列中
  4. unlock(&mutex);
  5. 当前等待的线程阻塞 <<== 等待其他线程通知唤醒(signal 或 broadcast)
  6. 在唤醒后,lock(&mutex)
  7. 从等待队列中删除线程自己

41.2 例子

  一个线程负责计算结果,一个线程负责获取结果

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <pthread.h>
 4 #include <unistd.h>
 5
 6 /** 两个线程定义的共享资源 */
 7 typedef struct {
 8     int res;
 9     int is_wait;    ///< 用户给出的用于判断的条件
10     pthread_cond_t cond;    ///< 条件变量
11     pthread_mutex_t mutex;  ///< 互斥锁
12 }Result;
13
14
15 /** 计算并将结果放置在 Result 中的线程运行函数 */
16 void *set_fn(void *arg)
17 {
18     Result *r = (Result *)arg;
19     int i = 0;
20     int sum = 0;
21
22     for(; i <= 100; i++){
23         sum += i;
24     }
25
26     /** 将结果放置到 Result 中 */
27     r->res = sum;
28
29     pthread_mutex_lock(&r->mutex);
30     /** 判断获取结果的线程是否准备好 */
31     while(!r->is_wait){
32         pthread_mutex_unlock(&r->mutex);
33         usleep(100);
34         pthread_mutex_lock(&r->mutex);
35     }
36     pthread_mutex_unlock(&r->mutex);
37
38     /** 通知唤醒等待的那个获取结果的线程 */
39     pthread_cond_broadcast(&r->cond);
40
41     return (void *)0;
42 }
43
44 /** 获得结果的线程运行函数 */
45 void *get_fn(void *arg)
46 {
47     Result *r = (Result *)arg;
48
49     /** 对两个线程共享的判断条件进行保护(加锁) */
50     /** 两个线程对判断条件的操作是互斥的 */
51     pthread_mutex_lock(&r->mutex);
52     /** 当线程启动后,将此变量设置为1,代表此线程已经准备好了 */
53     r->is_wait = 1;
54
55     /** 获取结果的线程等待 */
56     pthread_cond_wait(&r->cond, &r->mutex);
57
58     /** 被唤醒后 */
59     pthread_mutex_unlock(&r->mutex);
60
61     /** 去获取计算结果 */
62     int res = r->res;
63     printf("0x%lx get sum is %d\n", pthread_self(), res);
64
65     return (void *)0;
66 }
67
68 int main(void)
69 {
70     int err;
71     pthread_t cal, get;
72
73     Result r;
74     r.is_wait = 0;
75     pthread_cond_init(&r.cond, NULL);
76     pthread_mutex_init(&r.mutex, NULL);
77
78     /** 启动获取结果的线程 */
79     if((err = pthread_create(&get, NULL, get_fn, (void *)&r)) != 0){
80         perror("pthread create error");
81     }
82
83     /** 启动计算结果的线程 */
84     if((err = pthread_create(&cal, NULL, set_fn, (void *)&r)) != 0){
85         perror("pthread create error");
86     }
87
88     pthread_join(cal, NULL);
89     pthread_join(get, NULL);
90
91     pthread_cond_destroy(&r.cond);
92     pthread_mutex_destroy(&r.mutex);
93
94     pthread_cond_destroy(&r.cond);
95     pthread_mutex_destroy(&r.mutex);
96     return 0;
97 }

  编译执行结果:

  

原文地址:https://www.cnblogs.com/kele-dad/p/10230340.html

时间: 01-11

四十一、Linux 线程——线程同步之条件变量的相关文章

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

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

C++11 中的线程、锁和条件变量

转自:http://blog.jobbole.com/44409/ 线程 类std::thread代表一个可执行线程,使用时必须包含头文件<thread>.std::thread可以和普通函数,匿名函数和仿函数(一个实现了operator()函数的类)一同使用.另外,它允许向线程函数传递任意数量的参数. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <thread> void func() {    // do some work } int

【转】【C++】C++ 中的线程、锁和条件变量

线程 类std::thread代表一个可执行线程,使用时必须包含头文件<thread>.std::thread可以和普通函数,匿名函数和仿函数(一个实现了operator()函数的类)一同使用.另外,它允许向线程函数传递任意数量的参数. #include <thread> void func() { // do some work } int main() { std::thread t(func); t.join(); return 0; } 上例中,t 是一个线程对象,函数fu

Linux多线程实践(8) --Posix条件变量解决生产者消费者问题

Posix条件变量 int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr); int pthread_cond_destroy(pthread_cond_t *cond); int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); int pthread_cond_timedwait(pthread_cond_t *cond

linux C++ 多线程使用pthread_cond 条件变量

1. 背景 多线程中经常需要使用到锁(pthread_mutex_t)来完成多个线程之间的互斥操作. 但是互斥锁有一个明显到缺点: 只有两种状态,锁定和非锁定. 而条件变量则通过允许线程阻塞并等待另一个线程发送唤醒信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用. 2. 条件变量涉及到的主要函数 2.1 pthread_cond_wait 线程阻塞在条件变量 int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex); 函

线程同步(条件变量、信号量)以及死锁

死锁:指两个或两个以上进程(或线程)在执行过程中,因争夺资源而造成的一种互相等待现象,若无外力作用,它们都将无法继续推进下去. 例:交叉死锁:线程1获得了锁1,线程2获得了锁2,此时线程1调用lock想获得锁2,需挂起等待线程2释放锁2,而线程2也想获得锁1,也需挂起等待线程1释放锁1,此时两个线程都挂起等待 产生死锁的四个必要条件: (1):互斥条件(一个资源每次只能被一个进程或线程使用) (2):请求与保持条件(一个进程或线程因请求资源而阻塞时,对已获得的资源不释放) (3):不剥夺条件(此

线程同步之——条件变量

一.生产消费模型:我们可以用条件变量来实现线程之间的同步,利用一个生产消费模型具体的实现同步.生产消费模型可以简单地称为3,2,1模型(即3种关系,2个对象,1个场所),同时还需注意以下3点: 1.生产者和消费者是同步互斥关系: 2.生产者和生产者是互斥关系: 3.消费者和消费者是互斥关系. 二.条件变量的理解:线程A需要等某个条件成才能继续往下执,现在这个条件不成,线程A就阻塞等待,线程B在执过程中使这个条件成了,就唤醒线程A继续执. 在pthread库中通过条件变量(Condition Va

使用线程间通信之条件变量

最近用C++写安卓下的一个通讯程序,作为jni库给java调用,采用多线程轮询遇到一个问题描述如下: A线程收到数据,放入队列,是生产者. B.C.D若干个线轮询训消息队列,如果队列有数据就取出进行处理,没数据就Sleep(T)休息,问题是这个T值取多大合适?取大了消息处理不及时,取小了手机cpu上升电池很快耗光. 这个问题最佳解法是采用条件变量,可以比较完美解决问题,以下代码使用C++封装,用win32 SDK的条件变量举例,Linux下有完全等价的概念: // 线程消息通知 class Th

详解linux互斥锁 pthread_mutex和条件变量pthread_cond

[cpp] view plaincopy ============================================================= int pthread_create( pthread_t *tid, const pthread_attr_t *attr, void*(*start_routine)(void*), void *arg ); //参数tid 用于返回新创建线程的线程号: //start_routine 是线程函数指针,线程从这个函数开始独立地运

Linux环境下线程消息同步的陷阱

我们程序中常常会使用到线程间的消息同步处理,比如以下一段伪码 var message = "": void func()  {   1. 启动线程Thread(该线程中填充message的内容):   2. 阻塞,直到等待到完成message填充的事件:   3. 处理message:   .... } void Thread()  {   1. 通过某种处理填充message:   2. 触发func中的阻塞事件: } 我们通常会使用条件变量来完成类似情况的线程同步处理 比如wind