条件变量

boost::condition

程序如下,main函数里要把上面两个线程的join交换一下,先执行线程2,这样在线程2里的随机数如果大于90,会唤醒线程1。如果先执行线程1,会一直阻塞,程序没法向下执行了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include<ros/ros.h>
#include <boost/thread.hpp>
#include "boost/thread/mutex.hpp"
#include <boost/thread/condition.hpp>
using namespace std;

boost::mutex mut;
boost::condition cond;
boost::mutex::scoped_lock _lock(mut);

void thread_1(int n)
{
while(true)
{
// 线程1在这里阻塞,但先解开互斥锁,让其他线程能够得到这个互斥锁
cond.wait(_lock);
cout<< "thread 1: "<< rand()%50 <<endl;
sleep(1);
}
}

void thread_2(int n)
{
int m;
while(true)
{
m = 50 + rand()%50;
cout<< "thread 2: "<< m <<endl;
if(m > 90)
{
// 发送一个信号给另外一个阻塞的线程,使其继续执行
cond.notify_one();
cout<<"thread 2 wake thread 1 ";
}
sleep(1);
}
}

int main()
{
unsigned int n = 2;
boost::thread th_1 = boost::thread(boost::bind(&thread_1,n));
boost::thread th_2 = boost::thread(boost::bind(&thread_2,n));

th_1.join();
th_2.join();
return 0;
}

某次的测试结果:

1
2
3
4
5
6
7
thread 2: 65
thread 2: 93
thread 2 wake thread 1 thread 1: 35
thread 2: 86
thread 2: 92
thread 2 wake thread 1 thread 1: 49
thread 2: 71

条件变量的一般用法是:线程 A 等待某个条件并挂起,直到线程 B 满足了这个条件,并通知条件变量,然后线程 A 被唤醒。经典的生产者-消费者问题就可以用条件变量来解决。

这里等待的线程可以是多个,notify_one是通知一个线程,若有多个线程在等待,则根据优先级高低和入队顺序决定取消哪个线程,当然也可以使用notify_all是激活所有线程。

多个等待线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include<ros/ros.h>
#include <boost/thread.hpp>
#include "boost/thread/mutex.hpp"
#include <boost/thread/condition.hpp>
using namespace std;

boost::mutex mut, mut_2;
boost::condition cond;

// 线程1和线程2 必须使用不同的 scoped_lock
boost::mutex::scoped_lock lock(mut);
boost::mutex::scoped_lock lock_2(mut_2);

void thread_1(int n)
{
while(true)
{
cout << " ----- thread 1 is blocking ----- " << endl;
cond.wait(lock);
cout<< " ++++++++++++++ thread 1: "<< rand()%50 << " ++++++++++++++" << endl;
sleep(1);
}
}

void thread_2(int n)
{
while(true)
{
cout << " ----- thread 2 is blocking ----- " << endl;
cond.wait(lock_2);
cout<< " ************ thread 2: "<< rand()%50 << " ************" << endl;
sleep(1);
}
}

void thread_3(int n)
{
int m;
while(true)
{
m = 50 + rand()%50;
cout<< "thread 3: "<< m <<endl;
if(m > 88)
{
// 唤醒一个
cond.notify_one();
cout<<" ------------------ thread 3 wake a thread ------------------ " <<endl;
}
sleep(1);
}
}

int main()
{
unsigned int n = 2;
boost::thread th_1 = boost::thread(boost::bind(&thread_1,n));
boost::thread th_2 = boost::thread(boost::bind(&thread_2,n));
boost::thread th_3 = boost::thread(boost::bind(&thread_3,n));

th_1.join();
th_2.join();
th_3.join();
return 0;
}

一次的运行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 ----- thread 1 is blocking ----- 
thread 3: 83
----- thread 2 is blocking -----
thread 3: 86
thread 3: 77
thread 3: 65
thread 3: 93
------------------ thread 3 wake a thread ------------------
++++++++++++++ thread 1: 35 ++++++++++++++
----- thread 1 is blocking -----
thread 3: 86
thread 3: 92
------------------ thread 3 wake a thread ------------------
************ thread 2: 49 ************
thread 3: ----- thread 2 is blocking ----- 71

thread 3: 62
thread 3: 77
thread 3: 90
------------------ thread 3 wake a thread ------------------
++++++++++++++ thread 1: 9 ++++++++++++++

线程2在线程1之后,所以线程3会先激活线程1,然后线程2

notify_all就会激活两个线程,不列举结果了。