【C++并发实战1】
来源:互联网 发布:手机放大镜软件 编辑:程序博客网 时间:2024/06/05 19:55
首先确定安装了boost
if(boost没安装)
{
return;
}
1 编写如下文件:
#include <iostream>#include "boost\thread.hpp"using namespace std;void show(){ cout<<"hello world "<<endl; } int main(){ boost::thread t(show);//这里还可以t(&show)也能成功, 和pthread_create一样 cout<<"main pid "<<" "<<t.get_id()<<endl; if(!t.joinable()) cout<<"thread unjoinable"<<endl; else{ cout<<"thread joinable"<<endl; t.join(); } return 0; }
程序输出:
main pid 1e00
thread joinable
hello world
(2、3行顺序不一定)
2 boost::thread可以接收一个函数对象作为参数 ,函数对象会被拷贝进线程空间,那么这里就要注意一个问题:拷贝语义,若必要请采用深拷贝
#include <iostream>#include "boost\thread.hpp"using namespace std;class test{ public: void operator()() const{ cout<<"operator() "<<*data<<endl; } test(int a=10){ cout<<"constructor"<<endl; data=new int(a); } int get() const{ return *data; } test(const test& one){ cout<<"copy constructor"<<endl; data=new int(one.get());//深拷贝,否则段错误 [1]} private: int* data; }; int main(){ test one; boost::thread myThread(one);//函数对象被拷贝进线程空间 myThread.join(); return 0; }
程序输出:
constructor
copy constructor
copy constructor(为什么会有两次拷贝?是有一个临时对象做中转吗?)
operator() 10
前三行的输出是在主线程中输出的,最后一行是在新建线程中输出的
如果把[1]所在行data=new int(one.get());注释掉,程序输出:
constructor
copy constructor
copy constructor
段错误 (核心已转储) //这里采用深拷贝可以消除段错误
3可以向thread传递临时函数对象
#include <iostream>#include "boost\thread.hpp"using namespace std;class test{ public: void operator()() const{ cout<<"operator() "<<*data<<endl; } test(int a=10){ cout<<"constructor"<<endl; data=new int(a); } int get() const{ return *data; } test(const test& one){ cout<<"copy constructor"<<endl; data=new int(one.get());//深拷贝,否则段错误 } private: int* data; }; int main(){ //boost::thread myThread(test());//错误,会被误以为一个无参数的函数指针并返回一个test对象,从而返回一个thread对象而不是启动线程 boost::thread myThread((test()));//多余的括号用于防止被解释为一个函数 //boost::thread myThread{test()};//书上这种用法,编译通不过 //也可以用函数对象test one(11);thread myThread(one); myThread.join(); return 0; }
输出结果:
constructor
copy constructor
copy constructor
operator() 10
前三行的输出是在主线程中输出的,最后一行是在新建线程中输出的
4thread结合boost::bind使用
#include <iostream>#include "boost\thread.hpp"#include "boost\bind.hpp"using namespace std;void show(int i){ cout<<"show() i="<<i<<endl; } int main(){ boost::thread t(boost::bind(show, 100)); //或boost::thread t(boost::bind(&show, 100));t.join(); return 0; }
程序输出:
show() i=100
5 thread还可以结合lambda表达式使用(lambda表达式不熟悉~待完善)
线程可能先于join完成,此时仍joinable
#include <iostream>#include "boost\thread.hpp"#include <windows.h>using namespace std;void show(){ cout<<"thread show()"<<endl; } int main(){ boost::thread t(show); Sleep(1); if(t.joinable()){ cout<<"joinable"<<endl; t.join(); } else{ cout<<"unjoinable"<<endl; } return 0; }
程序输出:
thread show()
joinable
6当detach线程后,线程生命周期可能长于thread对象
#include <iostream>#include "boost\thread.hpp"#include <Windows.h>using namespace std;void show(){ Sleep(1); cout<<"thread show"<<endl; } int main(){ { boost::thread t(show); t.detach(); } Sleep(10); return 0; }
程序输出:
thread show
7当一个thread对象销毁前,必须显示的指定是join还是detach线程(必须保证join和detach的正确,即使在异常抛出中。在thread对象销毁前作join或detach),否则一旦线程对象销毁后,thread析构函数会调用terminate()结束线程。如下:
#include <iostream>#include "boost\thread.hpp"#include <windows.h>using namespace std;void fun(){ for(int i=0;i<5;i++){ cout<<"thread::fun()"<<endl; Sleep(1); } } int main(){ { boost::thread t(fun); } cout<<"main exit"<<endl; Sleep(2); return 0; }
程序输出:
main exit
thread::fun() //子线程并没有输出5个thread::fun()说明被提前terminate了
8如果不等待线程完成,一定要确保线程存取的对象是有效的。比如:当线程函数持有一个局部变量的引用或指针时,但是这个局部变量缺被销毁了。
#include <iostream>#include "boost\thread.hpp"using namespace std;void do_something(int& i){ i++; cout<<i<<" "; } class func{ public: func(int& i):i_(i){} void operator()(){ for(int j=0;j<100;j++) do_something(i_); } public: int &i_; }; void oops(){ int local=0; func my_func(local); boost::thread my_thread(my_func); my_thread.detach();//分离线程 cout<<"oops() "<<local<<endl;//局部对象将会被销毁,do_something输出会出错 } int main(){ oops(); return 0; }
程序输出:
oops() 0 //局部对象已经被销毁
1 2 3 4 5 6 1 //预想是输出1-100的数,最后一个“1”已经是错误数据了
说明:子线程my_thread被分离后,oops()退出使局部对象my_func析构了(local也销毁了),此时子线程调用do_something()访问一个已经销毁的对象,从而错误。解决的办法是:子线程将数据拷贝到自己空间,从而替代共享数据的访问。这个问题类似于对象生命周期的管理,出现了析构竞态,也可以采用boost::shared_ptr管理对象的生命周期。
[转自http://blog.csdn.net/liuxuejiang158blog/article/details/17025577, 有改动]
- 【C++并发实战1】
- c++并发编程实战(1)
- Java并发编程实战(1)
- 【Java并发编程实战】—–“J.U.C”:Condition
- 【Java并发编程实战】—–“J.U.C”:Semaphore
- 【Java并发编程实战】—–“J.U.C”:ReentrantReadWriteLock
- 【Java并发编程实战】-----“J.U.C”:CyclicBarrier
- 【Java并发编程实战】—–“J.U.C”:CyclicBarrier
- 【Java并发编程实战】—–“J.U.C”:CountDownlatch
- 【Java并发编程实战】—–“J.U.C”:Phaser
- 【Java并发编程实战】-----“J.U.C”:Exchanger
- 【Java并发编程实战】—–“J.U.C”:Condition
- 【Java并发编程实战】—–“J.U.C”:Semaphore
- 【Java并发编程实战】—–“J.U.C”:ReentrantReadWriteLock
- 【Java并发编程实战】—–“J.U.C”:CyclicBarrier
- 【Java并发编程实战】—–“J.U.C”:CountDownlatch
- 【Java并发编程实战】—–“J.U.C”:Phaser
- 【Java并发编程实战】-----“J.U.C”:Exchanger
- PageRank算法研究
- OC-Protocol实现业务代理
- 第2次实验 - 算法基本功与综合思考
- Chromium WebView
- uva 10034(最小生成树)
- 【C++并发实战1】
- 数据库相关
- Sublime Text User Settings
- NoSQL相关
- swift 笔记 (十一) —— 方法(类,结构体,枚举)
- 【剑指offer】面试题5:从尾到头打印链表
- 自动装箱与拆箱中的陷阱
- Boost.Asio C++ Network Programming(Chapter 2)
- Google 服务器 IP 地址列表