第2章中,我们将了解一下用于管理线程的类和函数
本章主要内容
- 启动新线程
- 等待线程与分离线程
- 线程唯一标识符
使用C++线程库启动线程,可以归结为构造 std::thread 对象:
void do_some_work(); |
std::thread my_thread(do_some_work); |
注意,当把函数对象传入到线程构造函数中时,需要避免"最令人头痛的语法解析"(C++'s most vexing parse, 中文简介)。如果你传递了一个临时变量,而不是一个命名的变量;C++编译器会将其解析为函数声明,而不是类型对象的定义。
例如:
std::thread my_thread(background_task()); |
这里相当与声明了一个名为my_thread的函数,这个函数带有一个参数(函数指针指向没有参数并返回background_task对象的函数),返回一个 std::thread 对象的函数,而非启动了一个线程。
解决方法:
使用在前面命名函数对象的方式,或使用多组括号①,或使用新统一的初始化语法②,可以避
免这个问题。
如下所示:
|
|
|
2.1.2 等待线程完成
如果需要等待线程,相关的 std::tread 实例需要使用join()。清单2.1中,将 my_thread.detach() 替换为 my_thread.join() ,就可以确保局部变量在线程完成后,才被销毁。
join()是简单粗暴的等待线程完成或不等待。当你需要对等待中的线程有更灵活的控制时,比
如,看一下某个线程是否结束,或者只等待一段时间(超过时间就判定为超时)。想要做到这
些,你需要使用其他机制来完成,比如条件变量和期待(futures)
2.1.4 后台运行线程
清单2.4 使用分离线程去处理其他文档
void edit_document(std::string const& filename) { open_document_and_display_gui(filename); while(!done_editing()) { user_command cmd=get_user_input(); if(cmd.type==open_new_document) { std::string const new_name=get_filename_from_user(); std::thread t(edit_document,new_name); // 1 t.detach(); // 2 } else { process_user_input(cmd); } } } |
如果用户选择打开一个新文档,为了让迅速打开文档,需要启动一个新线程去打开新文档①,
并分离线程②。与当前线程做出的操作一样,新线程只不过是打开另一个文件而已。所以,
edit_document函数可以复用,通过传参的形式打开新的文件。
十一
•