四十一、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

时间: 2024-09-29 23:46:30

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

Linux程序设计学习笔记----多线程编程之线程同步之条件变量

转载请注明出处:http://blog.csdn.net/suool/article/details/38582521. 基本概念与原理 互斥锁能够解决资源的互斥访问,但是在某些情况下,互斥并不能解决问题,比如两个线程需 要互斥的处理各自的操作,但是一个线程的操作仅仅存在一种条件成立的情况下执行,一旦错过不可再重现,由于线程间相互争夺cpu资源,因此在条件成立的时候,该线程不一定争夺到cpu而错过,导致永远得不到执行..... 因此需要某个机制来解决此问题,更重要的是,线程仅仅只有一种情况需要执

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

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

linux线程间通信之条件变量和互斥量

一.条件变量定义 有的时候仅仅依靠锁住共享资源来使用它是不够的.有时候共享资源只有某些状态的时候才能够使用.比方说,某个线程如果要从堆栈中读取数据,那么如果栈中没有数据就必须等待数据被压栈.这种情况下的同步使用互斥锁是不够的.另一种同步的方式--条件变量,就可以使用在这种情况下.条件变量(Condition Variable)是线程间的一种同步机制,提供给两个线程协同完成任务的一种方法,使用条件变量可以以原子方式阻塞线程,直到某个特定条件为真为止.条件变量的测试一般是用互斥量来保护的,用来确保每

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); 函

四十二、Linux 线程——线程同步之条件变量之线程状态转换

42.1 线程状态转换 42.1.1 状态转换图 42.1.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 counter; ///< 用于统计获取结果线程的数量 10 p

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

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