boost::thread编程实战(1)——创建线程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014454538/article/details/88049397

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
    一个线程只能被调用一次,如果在joinablefalse的情况下调用,会直接抛出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

猜你喜欢

转载自blog.csdn.net/u014454538/article/details/88049397