Boost多线程库的引用
调用Boost多线程库。
1#include <iostream>
2#include <boost/thread/thread.hpp>
3//typedef void
4
5
6void hello()
7 { std::cout << "Hello world, I'm a thread!" << std::endl;
8
9 }
10
11int main()
12{
13 std::cout << "Hello World!\n";
14
15 boost::thread thrd(&hello); //Boost多线程
16 thrd.join(); //启动线程
17 std::cin.get();//等待输入
18 return 0;
19
20}
运行结果:
Boost线程互斥
对线程需要竞争访问的变量可以互斥上锁。既可以实现竞争但有序的使用资源。
互斥体(mutex,mutual exclusion的缩写)
Boost线程库支持两大类互斥体,包括简单互斥体(simple mutex)和递归互斥体(recursive mutex)
递归互斥体可以多次上锁。
//Boost提供六种互斥体类型
boost::mutex,
boost::try_mutex,
boost::timed_mutex,
boost::recursive_mutex,
boost::recursive_try_mutex,
boost::recursive_timed_mutex
1#include <iostream>
2#include <boost/thread/thread.hpp>
3#include <boost/thread/mutex.hpp>
4
5boost::mutex io_mutex;
6struct count //定义函数对象
7{
8 count(int id) : id(id) { }
9 void operator()()
10 {
11 for (int i = 0; i < 100; ++i)
12 {
13 //boost::mutex::scoped_lock lock(io_mutex); //scoped_lock模式,开启注释即开启互斥
14 //类scoped_lock是提供便利RAII风格机制的互斥包装器,它在作用域块的存在期间占有一个
15 //
16 //
17 //建议统一用升级过后的的scoped_lock
18 std::cout << id << ": " << i << std::endl; //共享资源为为std:cout
19 }
20 }
21 int id;
22 };
23
24 int main(int argc, char* argv[])
25{
26 boost::thread thrd1(count(1)); //线程1,id=1
27 boost::thread thrd2(count(2));//线程2,id=2
28 thrd1.join();
29 thrd2.join();
30 return 0;
31 }
不使用互斥结果:
使用互斥的结果:
或者可以使用绑定方式,避免使用函数对象。
1 #include <boost/thread/thread.hpp>
2 #include <boost/thread/mutex.hpp>
3 #include <boost/bind.hpp>
4 #include <iostream>
5
6 boost::mutex io_mutex1;
7 void count(int id)
8 {
9 for (int i = 0; i < 100; ++i)
10 {
11 boost::mutex::scoped_lock
12 lock(io_mutex1);
13 std::cout << id << ": " <<
14 i << std::endl;
15 }
16 }
17
18 int main(int argc, char* argv[])
19 {
20 boost::thread thrd1(
21 boost::bind(&count, 1)); //使用boostBind避免使用函数对象
22 boost::thread thrd2(
23 boost::bind(&count, 2));
24 thrd1.join();
25 thrd2.join();
26 return 0;
27 }
条件变量
条件变量即Boost线程库中的信号量。
条件变量的使用总是和互斥体及共享资源联系在一起的。线程首先锁住互斥体,然后检验共享资源的状态是否处于可使用的状态。
如果不是,那么线程就要等待条件变量。要指向这样的操作就必须在等待的时候将互斥体解锁,以便其他线程可以访问共享资源并改变其状态。
它还得保证从等到得线程返回时互斥体是被上锁的。当另一个线程改变了共享资源的状态时,它就要通知正在等待条件变量得线程,并将之返回等待的线程。
下面是一个使用了boost::condition的简单例子。有一个实现了有界缓存区的类和一个固定大小的先进先出的容器。
由于使用了互斥体boost::mutex,这个缓存区是线程安全的。put和get使用条件变量来保证线程等待完成操作所必须的状态。
有两个线程被创建,一个在buffer中放入100个整数,另一个将它们从buffer中取出。这个有界的缓存一次只能存放10个整数,所以这两个线程必须周期性的等待另一个线程。
为了验证这一点,put和get在std::cout中输出诊断语句。最后,当两个线程结束后,main函数也就执行完毕了。
1
2 #include <boost/thread/thread.hpp>
3 #include <boost/thread/mutex.hpp>
4 #include <boost/thread/condition.hpp> //条件变量
5 #include <iostream>
6
7
8 const int BUF_SIZE = 10;
9 const int ITERS = 100;
10boost::mutex io_mutex2;
11 class buffer
12{
13public:
14 typedef boost::mutex::scoped_lock
15 scoped_lock;
16 buffer() : p(0), c(0), full(0) { }
17
18 void put(int m)
19 {
20 scoped_lock lock(mutex);
21 if (full == BUF_SIZE)
22 {
23 {
24 boost::mutex::scoped_lock
25 lock(io_mutex2);
26 std::cout <<
27 "Buffer is full. Waiting..." << std::endl;
28 }
29 while (full == BUF_SIZE)
30 cond.wait(lock);
31 }
32 buf[p] = m;
33 p = (p + 1) % BUF_SIZE;
34 ++full;
35 cond.notify_one();
36 }
37
38 int get()
39 {
40 scoped_lock lk(mutex);
41 if (full == 0)
42 {
43 {
44 boost::mutex::scoped_lock
45 lock(io_mutex2);
46 std::cout << "Buffer is empty. Waiting..." << std::endl;
47 }
48 while (full == 0)
49 cond.wait(lk);
50 }
51 int i = buf[c];
52 c = (c + 1) % BUF_SIZE;
53 --full;
54 cond.notify_one();
55 return i;
56 }
57
58 private:
59 boost::mutex mutex;
60 boost::condition cond;
61 unsigned int p, c, full;
62 int buf[BUF_SIZE];
63 };
64
65 buffer buf;
66
67 void writer()
68 {
69 for (int n = 0; n < ITERS; ++n)
70 {
71 {
72 boost::mutex::scoped_lock
73 lock(io_mutex2);
74 std::cout << "sending: " << n << std::endl;
75 }
76 buf.put(n);
77 }
78 }
79
80 void reader()
81 {
82 for (int x = 0; x < ITERS; ++x)
83 {
84 int n = buf.get();
85 {
86 boost::mutex::scoped_lock
87 lock(io_mutex2);
88 std::cout << "received: " << n << std::endl;
89 }
90 }
91 }
92
93 int main(int argc, char* argv[])
94 {
95 boost::thread thrd1(&reader);
96 boost::thread thrd2(&writer);
97 thrd1.join();
98 thrd2.join();
99 return 0;
100 }
线程局部存储
Boost线程库提供了智能指针boost::thread_specific_ptr来访问本地存储线程。每一个线程第一次使用这个智能指针的实例时,它的初值是NULL,所以必须要先检查这个它的只是否为空,并且为它赋值。Boost线程库保证本地存储线程中保存的数据会在线程结束后被清除。
从这个例子输出可以明白的看出每个线程都处理属于自己的数据实例,尽管它们都是使用同一个boost::thread_specific_ptr。
1 #include <boost/thread/thread.hpp>
2 #include <boost/thread/mutex.hpp>
3 #include <boost/thread/tss.hpp>
4 #include <iostream>
5
6 boost::mutex io_mutex3;
7 boost::thread_specific_ptr<int> ptr; //智能指针boost::thread_specific_ptr来访问本地存储线程
8
9 //<<二进制左移运算符
10 //<<二进制右移运算符
11
12struct count
13 {
14 count(int id) : id(id) { }
15 void operator()()
16 {
17 if (ptr.get() == 0)
18 ptr.reset(new int(0));
19 for (int i = 0; i < 10; ++i) //10次循环,每一次都会增加智能指针指向的值
20 {
21 (*ptr)++;
22 boost::mutex::scoped_lock lock(io_mutex3);
23 std::cout << id << ": " << *ptr << std::endl;
24 }
25 }
26 int id;
27 };
28
29 int main(int argc, char* argv[])
30 {
31 boost::thread thrd1(count(1));
32 boost::thread thrd2(count(2));
33 thrd1.join();
34 thrd2.join();
35 return 0;
36 }
单例运行
在多线程的方法中,使某个过程仅运行一次。常用于初始化过程中。
1 #include <boost/thread/thread.hpp>
2 #include <boost/thread/once.hpp>
3 #include <iostream>
4
5 int i = 0;
6 boost::once_flag flag = BOOST_ONCE_INIT; //定义标志
7
8 void init()
9 {
10 ++i;
11 }
12
13 void thread()
14 {
15 boost::call_once(&init, flag); //单次运行
16 }
17
18 int main(int argc, char* argv[])
19 {
20 boost::thread thrd1(&thread);
21 boost::thread thrd2(&thread);
22 thrd1.join();
23 thrd2.join();
24 std::cout << i << std::endl;
25 return 0;
26 }