1. A simple example
#include <iostream>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
using namespace boost;
void thread1(int x){
std::cout << "x= " << x << std::endl;
for (int i = 0; i < 10; i++){
std::cout << "thread1: " << i << std::endl;
}
}
void thread2(int x){
std::cout << "x= " << x << std::endl;
for (int i = 0; i < 10; i++){
std::cout << "thread2: " << i << std::endl;
}
}
int main(){
//boost::thread thrd1(&thread1, 2);//线程中传入函数thrd1 地址,并传入参数2
//boost::thread thrd2(&thread2, 3);
boost::thread thrd1(boost::bind(&thread1, 1));//使用boost::bind()函数,实现函数绑定
boost::thread thrd2(boost::bind(&thread2, 2));
thrd1.join();
thrd2.join();
return 0;
}
运行结果如下:
在上面的例子中,main函数是一个线程,新建的两个线程均用于输出函数参数x和1~100的数字。为了防止程序的终止,需要对新建的线程调用join()方法。join()方法是一个阻塞调用,暂停当前的线程,一直等到调用boost::thread::join()函数的线程运行结束。上例子中的main()函数会一直等待到thread()运行结束。
参考文档:
boost::thread多线程
boost多线程编程(一)
2. join()和detach()的区别
join()
:
①thread::join()
是个简单暴力的方法,当thread::join()
函数被调用后,主线程会被阻塞,直到子线程的执行被完成。主线程要等待启动的子线程完成,才会继续往下执行。
#include <iostream>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
using namespace boost;
void fun();
void thread1(int x){
std::cout << "x= " << x << std::endl;
for (int i = 0; i < 10; i++){
std::cout << "thread1: " << i << std::endl;
}
}
int main(){
boost::thread thrd1(boost::bind(&thread1, 1));//使用boost::bind()函数,实现函数绑定
thrd1.join();
std::cout << "this is main()" << std::endl;
return 0;
}
执行结果如下:
根据运行结果可以知道,只有子线程thrd1
执行完成后,主线程才会继续往下执行。
② 线程是可结合的(joinable
):用于判断线程是否是可结合的。
一个线程在未调用的情况下,joinable
的值为true
;一旦线程被join
过一次以后则变为false
。即使一个线程已经结束了,但是没有被join
过,还是会返回true
。
一个线程只能被调用一次,如果在joinable
为false
的情况下调用,会直接抛出std::system_error
。
将上面的程序的主函数修改如下:
int main(){
boost::thread thrd1(boost::bind(&thread1, 1));//使用boost::bind()函数,实现函数绑定
if (thrd1.joinable()){
thrd1.join();
}
if (!thrd1.joinable()){
std::cout << "thrd1 is unjionable" << std::endl;
}
std::cout << "this is main()" << std::endl;
return 0;
}
程序执行结果如下:
detach()
:
①thread::detach()
函数被调用后,主线程不会被阻塞,子线程会被放到后台运行,并且将管理权转给C++运行库。即如果选择分离(detach)
子线程,则主线程丧失对子线程的控制权,其控制权转交给 C++ 运行时库。detach方式,启动的子线程自主在后台运行,当前的代码继续往下执行,不等待子线程结束。
#include <iostream>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
using namespace boost;
void thread2(int x){
std::cout << "x= " << x << std::endl;
for (int i = 0; i < 10000; i++){
std::cout << "thread2: " << i << std::endl;
}
}
int main(){
boost::thread thrd2(boost::bind(&thread2, 2));
thrd2.detach();
std::cout << "this is main()" << std::endl;
std::cout << "this is main()" << std::endl;
std::cout << "this is main()" << std::endl;
std::cout << "this is main()" << std::endl;
return 0;
}
运行结果:
② 线程是可结合的(joinable
):与thread::join()
是一样的。
总结: 不论是thread::join()
或是 thread::detach()
,我们都首先调用了 joinable()
成员函数。它在尚未决定jion/detach
时,返回 true;而若已经决定了jion/detach
,则返回 false。
#include <iostream>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
using namespace boost;
void thread2(int x){
std::cout << "x= " << x << std::endl;
for (int i = 0; i < 10000; i++){
std::cout << "thread2: " << i << std::endl;
}
}
int main(){
boost::thread thrd2(boost::bind(&thread2, 2));
if (thrd2.joinable()){
thrd2.detach();
}
if (!thrd2.joinable()){
std::cout << "thrd2 is unjoinable" << std::endl;
}
std::cout << "this is main()" << std::endl;
std::cout << "this is main()" << std::endl;
std::cout << "this is main()" << std::endl;
std::cout << "this is main()" << std::endl;
return 0;
}
运行结果:
join()
和detach()
的区别总结:
① 当使用join方式时,会阻塞当前代码,等待线程完成退出后,才会继续向下执行;而使用detach方式则不会对当前代码造成影响,当前代码继续向下执行,创建的新线程同时并发执行,这时候需要特别注意:添加链接描述
(1)主线程结束之后,子线程可能仍在运行(因而可以作为守护线程);
(2)主线程结束伴随着资源销毁,需要保证子线程没有引用这些资源。
② 创建一个线程之后,我们还需要考虑一个问题:该如何处理这个线程的结束?
一种方式是等待这个线程结束,在一个合适的地方调用 thread 实例的 join() 方法
,调用者线程将会一直等待着目标线程的结束,当目标线程结束之后调用者线程继续运行;另一个方式是将这个线程分离,由其自己结束,通过调用 thread 实例的 detach() 方法
将目标线程置于分离模式。
③ 一个线程的 join()
方法与 detach()
方法只能调用一次,不能在调用了 join()
之后又调用 detach()
,也不能在调用 detach() 之后又调用 join()。在调用了 join() 或者 detach() 之后,该线程的 id 即被置为默认值(空线程),表示不能继续再对该线程作修改变化。
④ 如果没有调用 join() 或者 detach(),那么,在析构的时候,该线程实例将会调用 std::terminate(),这会导致整个进程退出,所以,如果没有特别需要,一般都建议在生成子线程后调用其 join() 方法等待其退出,这样子最起码知道这些子线程在什么时候已经确保结束。
参考链接:
使用 C++11 编写 Linux 多线程程序
程序员的自我修养(五):C++ 多线程编程初步
Boost C++11多线程
《C++ Concurrency In Action》读书笔记 - 线程管理
C++并发实战2:thread::join和thread::detach