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

函数将解锁mutex参数指向的互斥锁,并使当前线程阻塞在cv参数指向的条件变量上。被阻塞的线程可以被pthread_cond_signal函数,pthread_cond_broadcast函数唤醒,也可能在被信号中断后被唤醒。pthread_cond_wait函数返回时,相应的互斥锁将被当前线程锁定,即使是函数出错返回。pthread_cond_wait函数的返回并不意味着条件的值一定发生了变化,必须重新检查条件的值。最好的测试方法是循环调用pthread_cond_wait函数,并把满足条件的表达式置为循环的终止条件。
1 pthread_mutex_lock();
2 while (condition_is_false)
3     pthread_cond_wait();
4 pthread_mutex_unlock();
阻塞在同一个条件变量上的不同线程被唤醒的次序是不一定的。

2.2 pthread_cond_signal 线程被唤醒

int pthread_cond_signal(pthread_cond_t *cv);函数被用来释放被阻塞在指定条件变量上的一个线程。必须在互斥锁的保护下使用相应的条件变量。否则对条件变量的解锁有可能发生在锁定条件变量之前,从而造成死锁。唤醒阻塞在条件变量上的所有线程的顺序由调度策略决定,如果线程的调度策略是SCHED_OTHER类型的,系统将根据线程的优先级唤醒线程。如果没有线程被阻塞在条件变量上,那么调用pthread_cond_signal()将没有作用。

更多函数可以看: http://blog.csdn.net/icechenbing/article/details/7662026

3. 实例代码

实现功能: 2个线程对count每次分别加1, 第三个线程等count大于10后一次加100.

3.1 加1线程函数

 1 void *inc_count(void *idp)
 2 {
 3     int i = 0;
 4     int taskid = 0;
 5     int *my_id = (int*)idp;
 6
 7     for (i=0; i<TCOUNT; i++) {
 8         pthread_mutex_lock(&count_mutex);
 9         taskid = count;
10         count++;
11
12         /*
13           唤醒一个阻塞在该条件变量到线程
14           如果没有线程被阻塞在条件变量上,那么调用pthread_cond_signal()将没有作用
15         */
16         pthread_cond_signal(&count_threshold_cv);
17
18         printf("inc_count(): thread %d, count = %d, unlocking mutex\n", *my_id, count);
19         pthread_mutex_unlock(&count_mutex);
20         sleep(1);
21     }
22     printf("inc_count(): thread %d, Threshold reached.\n", *my_id);
23
24     pthread_exit(NULL);
25 } 

3.2 count满足条件后, 单次加100函数

 1 void *watch_count(void *idp)
 2 {
 3     int *my_id = (int*)idp;
 4     printf("Starting watch_count(): thread %d\n", *my_id);
 5
 6     pthread_mutex_lock(&count_mutex);
 7     while(count<COUNT_LIMIT) {
 8         sleep(3);
 9         /*
10           函数将自动/原子的解锁count_mutex参数指向的互斥锁,并使当前线程阻塞在cv参数指向的条件变量上
11           被阻塞的线程可以被pthread_cond_signal函数,pthread_cond_broadcast函数唤醒,也可能在被信号中断后被唤醒
12           pthread_cond_wait函数的返回并不意味着条件的值一定发生了变化,必须重新检查条件的值.
13           本例子中线程被唤醒后, 仍然在while内会再次判断COUNT_LIMIT是否满足条件的值
14           pthread_cond_wait函数返回时,相应的互斥锁将被当前线程锁定,即使是函数出错返回
15         */
16         pthread_cond_wait(&count_threshold_cv, &count_mutex);
17         printf("watch_count(): thread %d Condition signal received.\n", *my_id);
18     }
19
20     count += 100;
21     pthread_mutex_unlock(&count_mutex);
22     pthread_exit(NULL);
23 }

3.3 整体代码

 1 #include <pthread.h>
 2 #include <stdio.h>
 3 #include <unistd.h>
 4
 5 #define NUM_THREADS 3
 6 #define TCOUNT      10
 7 #define COUNT_LIMIT 10
 8
 9 int count = 0;
10 int thread_ids[3] = {0,1,2};
11 pthread_mutex_t count_mutex;
12 pthread_cond_t  count_threshold_cv;
13
14 void *inc_count(void *idp)
15 {
16     int i = 0;
17     int taskid = 0;
18     int *my_id = (int*)idp;
19
20     for (i=0; i<TCOUNT; i++) {
21         pthread_mutex_lock(&count_mutex);
22         taskid = count;
23         count++;
24
25         /*
26           唤醒一个阻塞在该条件变量到线程
27           如果没有线程被阻塞在条件变量上,那么调用pthread_cond_signal()将没有作用
28         */
29         pthread_cond_signal(&count_threshold_cv);
30
31         printf("inc_count(): thread %d, count = %d, unlocking mutex\n", *my_id, count);
32         pthread_mutex_unlock(&count_mutex);
33         sleep(1);
34     }
35     printf("inc_count(): thread %d, Threshold reached.\n", *my_id);
36
37     pthread_exit(NULL);
38 }
39
40 void *watch_count(void *idp)
41 {
42     int *my_id = (int*)idp;
43     printf("Starting watch_count(): thread %d\n", *my_id);
44
45     pthread_mutex_lock(&count_mutex);
46     while(count<COUNT_LIMIT) {
47         sleep(3);
48         /*
49           函数将自动/原子到解锁mutex参数指向的互斥锁,并使当前线程阻塞在cv参数指向的条件变量上
50           被阻塞的线程可以被pthread_cond_signal函数,pthread_cond_broadcast函数唤醒,也可能在被信号中断后被唤醒
51           pthread_cond_wait函数的返回并不意味着条件的值一定发生了变化,必须重新检查条件的值.
52           本例子中使用类COUNT_LIMIT最为满足条件的值
53           pthread_cond_wait函数返回时,相应的互斥锁将被当前线程锁定,即使是函数出错返回
54         */
55         pthread_cond_wait(&count_threshold_cv, &count_mutex);
56         printf("watch_count(): thread %d Condition signal received.\n", *my_id);
57     }
58
59     count += 100;
60     pthread_mutex_unlock(&count_mutex);
61     pthread_exit(NULL);
62 }
63
64 int main (int argc, char *argv[])
65 {
66     int i, rc;
67     pthread_t threads[3];
68     pthread_attr_t attr;
69
70     /* Initialize mutex and condition variable objects */
71     pthread_mutex_init(&count_mutex, NULL);
72     pthread_cond_init (&count_threshold_cv, NULL);
73
74     /* For portability, explicitly create threads in a joinable state */
75     pthread_attr_init(&attr);
76     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
77     pthread_create(&threads[0], &attr, inc_count,   (void *)&thread_ids[0]);
78     pthread_create(&threads[1], &attr, inc_count,   (void *)&thread_ids[1]);
79     pthread_create(&threads[2], &attr, watch_count, (void *)&thread_ids[2]);
80
81     /* Wait for all threads to complete */
82     for (i=0; i<NUM_THREADS; i++) {
83         pthread_join(threads[i], NULL);
84     }
85     printf ("Main(): Waited on %d  threads. Done.\n", NUM_THREADS);
86
87     /* Clean up and exit */
88     pthread_attr_destroy(&attr);
89     pthread_mutex_destroy(&count_mutex);
90     pthread_cond_destroy(&count_threshold_cv);
91     pthread_exit(NULL);
92
93     return 0;
94 }

时间: 2024-10-17 22:14:18

linux C++ 多线程使用pthread_cond 条件变量的相关文章

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

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

详解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多线程编程的条件变量

在stackoverflow上看到一关于多线程条件变量的问题,题主问道:什么时候会用到条件变量,mutex还不够吗?有个叫slowjelj的人做了很好的回答,我再看这个哥们其他话题的一些回答,感觉水平好高的.这里把他的回答粘贴一下方便以后查看,原帖在这里:When is a conditional variable needed, isn't a mutex enough? Even though you can use them in the way you describe, mutexes

linux网络编程-----&gt;线程同步--&gt;条件变量

开发使用多线程过程中, 不可避免的会出现多个线程同时操作同一块共享资源, 当操作全部为读时, 不会出现未知结果, 一旦当某个线程操作中有写操作时, 就会出现数据不同步的事件. 而出现数据混乱的原因: 资源共享(独享资源则不会) 调试随机(对数据的访问会出现竞争) 线程间缺少必要的同步机制 以上三点, 前两点不能被改变. 欲提高效率, 传递数据, 资源必须共享. 只要资源共享, 就一定会出现线程间资源竞争, 只要存在竞争关系, 数据就会出现混乱. 所以只能从第三点着手, 使多个线程在访问共享资源的

多线程编程中条件变量和的spurious wakeup 虚假唤醒

1. 概述 条件变量(condition variable)是利用共享的变量进行线程之间同步的一种机制.典型的场景包括生产者-消费者模型,线程池实现等. 对条件变量的使用包括两个动作: 1) 线程等待某个条件, 条件为真则继续执行,条件为假则将自己挂起(避免busy wait,节省CPU资源): 2) 线程执行某些处理之后,条件成立:则通知等待该条件的线程继续执行. 3) 为了防止race-condition,条件变量总是和互斥锁变量mutex结合在一起使用. 一般的编程模式: C++代码  

多线程同步之条件变量

条件变量是线程同步的另一种手段,主要逻辑就是等待和唤醒.条件不满足时,线程等待:条件满足,线程被(其他线程)唤醒.条件变量一般和互斥量一起使用,因为需要保证多线程互斥地修改条件. 涉及到的函数有: int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr); int pthread_cond_destroy(pthread_cond_t *cond); int pthr

练习生产者与消费者-PYTHON多线程中的条件变量同步

以前练习过,但好久不用,手生,概念也生了, 重温一下.. URL: http://www.cnblogs.com/holbrook/tag/%E5%A4%9A%E7%BA%BF%E7%A8%8B/ ~~~~~~~ 互斥锁是最简单的线程同步机制,Python提供的Condition对象提供了对复杂线程同步问题的支持.Condition被称为条件变量,除了提供与Lock类似的acquire和release方法外,还提供了wait和notify方法.线程首先acquire一个条件变量,然后判断一些条件

python多线程编程(4): 条件变量同步

互斥锁是最简单的线程同步机制,Python提供的Condition对象提供了对复杂线程同步问题的支持.Condition被称为条件变量,除了提供与Lock类似的acquire和release方法外,还提供了wait和notify方法.线程首先acquire一个条件变量,然后判断一些条件.如果条件不满足则wait:如果条件满足,进行一些处理改变条件后,通过notify方法通知其他线程,其他处于wait状态的线程接到通知后会重新判断条件.不断的重复这一过程,从而解决复杂的同步问题. 可以认为Cond

python多线程编程5: 条件变量同步-乾颐堂

互斥锁是最简单的线程同步机制,Python提供的Condition对象提供了对复杂线程同步问题的支持.Condition被称为条件变量,除了提供与Lock类似的acquire和release方法外,还提供了wait和notify方法.线程首先acquire一个条件变量,然后判断一些条件.如果条件不满足则wait:如果条件满足,进行一些处理改变条件后,通过notify方法通知其他线程,其他处于wait状态的线程接到通知后会重新判断条件.不断的重复这一过程,从而解决复杂的同步问题. 可以认为Cond