boost::thread

1. 简介

thread 库为 c++增加了线程处理的能力,它提供简明清晰的线程、互斥量等概念,可以很容易地创建多线程应用程序。thread 库也是高度移植的,它支持使用最广泛的 Windows 和 POSIX 线程,用它编写的代码不需要修改就可以在Windows、UNIX等操作系统上编译运行。
thread 库也是boost库中少数需要编译才能使用的库,并且thread 库需要date_time 库支持,因此必须先编译date_time库。

2. thread 分析

在此,需要说明的是。这里并不会怎么针对 thread 的源码进行分析,thread 的实现是与具体的平台相关的,我们重点在于知道boost::thread 的用法就行。
从 thread 的构造函数我们知道 thread 可接受一个无参的可调用物(函数或函数对象),它必须具有operator()以供线程执行;如果可调用物不是无参的,那么 thread 的构造函数也支持直接传递所需的参数,这些参数将被拷贝并在发生调用时传递给函数。这是一个非常体贴方便的重载构造函数,比传统的使用void* 来传递参数要好很多。thread 的构造函数支持最多九个参数,这通常足够了,如果超过了,那么请检查代码设计是否有问题。
在传递参数时需要注意,thread 使用的是参数的拷贝,因此要求可调用物和参数类型都支持拷贝。如果希望传递给线程引用值就需要使用 ref 库进行包装,同时必须保证被引用的对象在线程执行期间一直存在,否则会引发为定义行为。

thread 类是 thread 库的核心类,负责启动和管理线程对象,在概念上和操作上都与POSIX线程很相似,因此如果对于POSIX线程熟悉的使用者来说,就比较熟悉。这里我们对于类 thread 的分析就以例子来做分析。

2.1 线程的启动

当成功创建一个 thread 对象后,线程就立刻开始执行, thread 不提供类似start()、begin()那样的方法。
通常,在 thread 的构造函数中写传递给调用函数的参数很麻烦,尤其是在使用大量线程对象的时候。这时我们可以使用 Boost 的 bind 和function 库:bind 库可以把函数所需的参数绑定到一个函数对象,而 function 则可以存储 bind 表达式的结果,供程序以后使用。

2.2 等待线程的结束

thread 的成员函数 joinable()可以判断 thread 对象是否标识了一个可执行的线程体。如果joinable()返回 true,我们就可以调用成员函数join()或者timed_join()来阻塞等待线程执行结束。两者的区别如下:
  • join()一直阻塞等待,直到线程结束;
  • timed_join() 阻塞等待线程结束,或者阻塞等待一定的时间段,然后不管线程是否结束都返回。注意,它不必阻塞等待指定的时间长度,如果在这段时间里线程运行结束,即使时间未到它也会返回。

2.3 与线程执行体分离

可以使用成员函数 detach() 将 thread 与线程执行体手动分离,此后 thread 对象不代表任何线程体,失去对线程的控制。
当 thread 与线程执行体分离时,线程执行体将不受影响地继续执行,直到运行结束,或者随主线程一起结束。
当线程执行完毕或者 thread 对象被销毁时,thread 对象也会自动与线程执行体分离,因此,当不需要操作线程体时,我们可以使用临时对象来启动一个线程。

下面的测试用例展示了 boost::thread 的最简单的使用场景:也就是创建某个线程,然后等待线程结束,程序终止。

/*********************************************************************************
*Copyright(C),Your Company
*FileName:  main.cpp
*Author:  Huangjh
*Version:
*Date:  2018-02-11
*Description:  boost::thread 的demo1
*Others:
**********************************************************************************/
#include 
#include 
#include 

using namespace std;
using namespace boost;

void wait(int iSeconds)
{
	this_thread::sleep(posix_time::seconds(iSeconds));
}

void threadFunction(void)
{
	for (int i = 0; i < 5; i++)
	{
		wait(1);
		cout << "threadFunction runnin time : " << i << endl;
	}
}

int main(void)
{
	cout << "boost thread test start ..." << endl;

	thread myThread(threadFunction);

	myThread.join();

	
	wait(10);

	return 0;
}
运行结果如下所示:

boost thread test start ...
threadFunction runnin time : 0
threadFunction runnin time : 1
threadFunction runnin time : 2
threadFunction runnin time : 3
threadFunction runnin time : 4
在上面的测试用例中,我们简单的创建了一个 thread 对象,在构造这个对象时候我们传入了某个函数指针。我们这边就简单的分析下 thread 对象的构造函数。

template <
         class F
       >
explicit thread(BOOST_THREAD_RV_REF(F) f
//, typename disable_if::type, thread>, dummy* >::type=0
):
thread_info(make_thread_info(thread_detail::decay_copy(boost::forward(f))))
{
	start_thread();
}
对于这个构造函数,我们需要先分析下BOOST_THREAD_RV_REF(F) f 的含义:

#define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(TYPE)

//!This macro is used to achieve portable syntax in move
//!constructors and assignments for classes marked as
//!BOOST_COPYABLE_AND_MOVABLE or BOOST_MOVABLE_BUT_NOT_COPYABLE
#define BOOST_RV_REF(TYPE)\
    TYPE && \
这里就涉及到一个概念:引用的折叠—— 一般来讲,我们不能定义一个引用的引用,但是通过类型别名或者模板参数可以间接定义。引用折叠是std::move、std::forward等的工作基础。如果对引用折叠有兴趣的朋友可以自行搜索下,这边就不多做说明。不过需要补充的是:引用折叠是服务于std::move、std::forward等的,而并不是服务于程序员的。只有在少数的情况下,程序员确实需要使用引用折叠来完成一些代码的设计。

接着看这个构造函数的实现,boost::forward 是有条件的转换为右值引用。thread_info(make_thread_info(thread_detail::decay_copy(boost::forward(f)))),老实说我也没去看。

detail::thread_data_ptr thread_info;

typedef boost::intrusive_ptr thread_data_ptr;
成员变量 thread_info 的类型为 detail::thread_data_ptr。是用于保存线程的数据用的。 

成员函数 start_thread()则启动线程。
成员函数join() 是一个阻塞调用:它可以暂停当前线程,直到 join() 的线程运行结束(其实和POSIX的join系统调用类似)。

 下面我们通过另外一个测试用例来说明如何通过所谓的中断点让一个线程中断。

/*********************************************************************************
*Copyright(C),Your Company
*FileName:  main.cpp
*Author:  Huangjh
*Version:
*Date:  2018-02-11
*Description:  boost::thread 的demo2
*Others:
**********************************************************************************/
#include 
#include 
#include 

using namespace std;
using namespace boost;

void wait(int iSeconds)
{
	this_thread::sleep(posix_time::seconds(iSeconds));
}

void threadFunction(void)
{
	try 
	{
		for (int i = 0; i < 5; i++)
		{
			wait(1);
			cout << "threadFunction runnin time : " << i << endl;
		}
	}
		catch (thread_interrupted &)
	{
		cout << "threadFunction interrupted ..." << endl;
	}
}

int main(void)
{
	cout << "boost thread test start ..." << endl;

	thread myThread(threadFunction);
	wait(3);

	myThread.interrupt();

	myThread.join();

	return 0;
}
运行结果如下所示:

boost thread test start ...
threadFunction runnin time : 0
threadFunction runnin time : 1
threadFunction interrupted ...
在一个线程对象上调用interript() 会中断相应的线程。在这方面,中断意味着一个类型为 boost::thread_interrupted 的异常,它会在这个线程中抛出。


















你可能感兴趣的:(boost::thread)