在Boost.Thread库中最重要的类是boost ::thread,它在boost/thread.hpp中定义。 该类用于创建新线程。 Example 44.1是一个创建线程的简单示例。
#include <boost/thread.hpp>
#include <boost/chrono.hpp>
#include <iostream>
void wait(int seconds)
{
boost::this_thread::sleep_for(boost::chrono::seconds{seconds});
}
void thread()
{
for (int i = 0; i < 5; ++i)
{
wait(1);
std::cout << i << '\n';
}
}
int main()
{
boost::thread t{thread};
t.join();
}
新线程应执行的函数的名称传递给boost::thread的构造函数。 在示例44.1中创建变量t之后,函数thread()立即开始在其自己的线程中执行。 此时,thread()与main()函数并发执行。
为了防止程序终止,在新创建的线程上调用join()。 join()会阻塞当前线程,直到调用join()终止线程为止。 这导致main()等待,直到thread()返回。
可以使用变量-在此示例中为t-来访问特定线程,以等待其终止。但是,即使t超出范围并被破坏,线程也将继续执行。一开始,线程始终绑定到boost :: thread类型的变量,但是一旦创建,线程就不再依赖于该变量。甚至还有一个名为detach()的成员函数,该函数允许将boost::thread类型的变量与其对应的线程解耦。在调用detach()之后,无法调用join()之类的成员函数,因为分离变量不再代表有效线程。
在函数内部可以完成的任何事情也可以在线程内部完成。最终,线程与函数没有什么不同,除了线程与另一个函数同时执行外。在例44.1中,五个数字被循环写入标准输出流。为了减慢输出速度,循环的每次迭代都会调用wait()函数来暂停一秒钟。 wait()使用sleep_for()函数,该函数也由Boost.Thread提供,并且位于命名空间boost::this_thread中。
sleep_for()希望有一个时间段作为其唯一参数,该时间段指示当前线程应暂停多长时间。通过传递类型为boost::chrono ::seconds的对象,可以设置一段时间。 boost::chrono::seconds来自第37章中介绍的Boost.Chrono。
sleep_for()仅接受Boost.Chrono的类型。即使Boost.Chrono已成为C ++ 11标准库的一部分,std::chrono中的类型也不能与Boost.Thread一起使用。这样做会导致编译器错误。
如果您不想在main()的末尾调用join(),则可以使用boost::scoped_thread类。
#include <boost/thread.hpp>
#include <boost/thread/scoped_thread.hpp>
#include <boost/chrono.hpp>
#include <iostream>
void wait(int seconds)
{
boost::this_thread::sleep_for(boost::chrono::seconds{seconds});
}
void thread()
{
for (int i = 0; i < 5; ++i)
{
wait(1);
std::cout << i << '\n';
}
}
int main()
{
boost::scoped_thread<> t{boost::thread{thread}};
}
boost::scoped_thread的构造函数需要一个boost:: thread类型的对象。 在boost::scoped_thread的析构函数中,一个动作可以访问该对象。 默认情况下,boost::scoped_thread使用一个在线程上调用join()的操作。 因此,示例44.2的工作方式类似于示例44.1。
您可以将用户定义的操作作为模板参数传递。 该操作必须是带有操作符operator()的类,该类接受boost::thread类型的对象。 boost::scoped_thread保证将在析构函数中调用该运算符。
您只能在Boost.Thread中找到类boost::scoped_thread。 标准库中没有对应项。 确保包含用于boost::scoped_thread的头文件boost/thread/scoped_thread.hpp。
例44.3引入了中断点,使中断线程成为可能。 中断点仅受Boost.Thread支持,而不受标准库支持。
#include <boost/thread.hpp>
#include <boost/chrono.hpp>
#include <iostream>
void wait(int seconds)
{
boost::this_thread::sleep_for(boost::chrono::seconds{seconds});
}
void thread()
{
try
{
for (int i = 0; i < 5; ++i)
{
wait(1);
std::cout << i << '\n';
}
}
catch (boost::thread_interrupted&) {}
}
int main()
{
boost::thread t{thread};
wait(3);
t.interrupt();
t.join();
}
在线程对象上调用interrupt()会中断相应的线程。在这种情况下,中断意味着在线程中引发了boost::thread_interrupted类型的异常。但是,只有在线程到达中断点时才会发生这种情况。
如果给定线程不包含中断点,则仅调用interrupt()无效。每当线程到达中断点时,它将检查是否已调用interrupt()。如果已调用,则会引发类型为boost::thread_interrupted的异常。
Boost.Thread定义了一系列中断点,例如sleep_for()函数。因为在示例44.3中将sleep_for()调用了五次,所以线程会检查它是否已被中断五次。在对sleep_for()的调用之间,线程不能被中断。
例44.3不显示五个数字,因为在main()中三秒钟后调用了interrupt()。因此,相应的线程被中断并引发boost ::thread_interrupted异常。即使catch处理程序为空,也可以在线程内部正确捕获异常。由于thread()函数在处理程序之后返回,因此线程也会终止。反过来,这将导致程序终止,因为main()正在等待线程终止。
Boost.Thread定义了大约15个中断点,包括sleep_for()。这些中断点使及时中断线程变得容易。但是,中断点不一定总是最好的选择,因为在线程可以检查boost::thread_interrupted异常之前必须达到中断点。
#include <boost/thread.hpp>
#include <boost/chrono.hpp>
#include <iostream>
void wait(int seconds)
{
boost::this_thread::sleep_for(boost::chrono::seconds{seconds});
}
void thread()
{
boost::this_thread::disable_interruption no_interruption;
try
{
for (int i = 0; i < 5; ++i)
{
wait(1);
std::cout << i << '\n';
}
}
catch (boost::thread_interrupted&) {}
}
int main()
{
boost::thread t{thread};
wait(3);
t.interrupt();
t.join();
}
类boost::this_thread::disable_interruption防止线程被中断。 如果实例化boost::this_thread::disable_interruption,则只要对象存在,线程中的中断点将被禁用。 因此,示例44.4显示了五个数字,因为忽略了中断线程的尝试。
#include <boost/thread.hpp>
#include <boost/chrono.hpp>
#include <iostream>
void wait(int seconds)
{
boost::this_thread::sleep_for(boost::chrono::seconds{seconds});
}
void thread()
{
try
{
for (int i = 0; i < 5; ++i)
{
wait(1);
std::cout << i << '\n';
}
}
catch (boost::thread_interrupted&) {}
}
int main()
{
boost::thread::attributes attrs;
attrs.set_stack_size(1024);
boost::thread t{attrs, thread};
t.join();
}
boost::thread::attributes用于设置线程属性。 在版本1.56.0中,您只能设置一个与平台无关的属性,即堆栈大小。 在示例44.5中,通过boost::thread :: attributes::set_stack_size()将堆栈大小设置为1024字节。
#include <boost/thread.hpp>
#include <iostream>
int main()
{
std::cout << boost::this_thread::get_id() << '\n';
std::cout << boost::thread::hardware_concurrency() << '\n';
}
在boost:: this_thread名称空间中,定义了适用于当前线程的独立函数。 这些功能之一是sleep_for(),我们之前已经看到过。 另一个是get_id(),它返回一个数字以唯一标识当前线程(请参见示例44.6)。 类boost::thread也将get_id()作为成员函数提供。
静态成员函数boost::thread::hardware_concurrency()根据CPU或CPU核心的基础数量返回可以在物理上同时执行的线程数。 在双核处理器上调用此函数将返回值2。此函数提供了一种简单的方法来确定理论上应使用的最大线程数。
Boost.Thread还提供了boost::thread_group类来管理组中的线程。 此类提供的一个函数,成员函数join_all(),等待组中的所有线程终止。
#include <boost/timer/timer.hpp>
#include <iostream>
#include <cstdint>
int main()
{
boost::timer::cpu_timer timer;
std::uint64_t total = 0;
for (int i = 0; i < 1'000'000'000; ++i)
total += i;
std::cout << timer.format();
std::cout << total << '\n';
}