发起线程
线程通过构建 std::thread
对象而启动,该对象指明线程要运行的任务。可以传入任何可调类型给 std::thread
来构建一个 std::thread
对象。 需要包含头文件 <thread>
。
- 传入的可调类型可以是函数:
void do_some_work();
std::thread my_thread(do_some_work);
- 传入的可调类型可以是带有函数调用操作符的类:
class background_task {
public:
void operator()() const {
do_something();
do_something_else();
}
};
background_task f;
std::thread my_thread(f);
此时要防范二义性,对于有可能被解释成函数声明的C++语句,编译器就肯定会将其解释为函数声明。如 std::thread my_thread(background_task());
语句本意是传入一个临时的匿名函数对象发起新线程,但却会被解释成一个函数声明。可以使用统一初始化语法来解决:
std::thread my_thread((background_task()));
std::thread my_thread{background_task()};
- 传入的可调类型可以是lambda表达式
std::thread my_thread([]{
do_something();
do_something_else();
});
必须时刻注意在线程运行结束前,要保证它所访问的外部数据必须始终正确、有效。尤其要注意传给线程的可调对象含有指针或引用时,引用的外部对象在线程运行期间是否可能会被销毁,是否可能出现悬空指针。
等待线程完成
std::thread my_thread(foo);
my_thread.join(); //等待线程结束
对于某个给定的线程,join()
只能调用一次,只要 std::thread
对象曾经调用过 join()
,线程就不再可汇合,成员函数 joinable()
将返回 false
。
利用 RAII 过程等待线程完成
如果打算等待线程结束,但在调用 join()
前就发生了异常,这会导致 join()
调用会被略过。为了在可能出现异常的情况下等待线程完成,最好是利用RAII过程。
RAII(Resource Acquisition Is Initialization),也称为“资源获取就是初始化”,是C++语言的一种管理资源、避免泄漏的惯用法。C++标准保证任何情况下,已构造的对象最终会销毁,即它的析构函数最终会被调用。简单的说,RAII 的做法是使用一个对象,在其构造时获取资源,在对象生命期控制对资源的访问使之始终保持有效,最后在对象析构的时候释放资源。
class thread_guard {
std::thread& t;
public:
explicit thread_guard(std::thread& t_) :t(t_) {}
~thread_guard() {
if (t.joinable()) t.join(); // join() 只能被调用一次
}
thread_guard(thread_guard const&) = delete; // 禁止拷贝构造函数
thread_guard& operator=(thread_guard const&) = delete; // 禁止赋值构造函数
};
struct func {
int& i;
func(int& i_) :i(i_) {}
void operator()() {
for (unsigned j = 0; j < 1000000; ++j)
do_something(i); // i是引用,需要注意可能导致悬空引用
}
};
void f() {
int some_local_state = 0;
func my_func(some_local_state);
std::thread t(my_func);
thread_guard(t);
do_something_in_current_thread();
}
当主线程执行到 f()
末尾时,按构建的逆序,所有局部对象都会被销毁,thread_guard
的对象 g
首先被销毁,在其析构函数中调用新线程的 join()
。即使 do_something_in_current_thread()
发生异常,g
的析构函数仍会被调用,以上行为仍会发生。
分离线程
std::thread my_thread(foo);
my_thread.detach(); //分离线程
只有 joinable()
返回 true
,线程才可被分离。分离后 joinable()
将返回 false
。
向线程函数传递参数
直接向 std::thread
的构造函数追加更多参数即可:
#include <iostream>
#include <thread>
void add(int a, int b) {
std::cout << a + b << std::endl;
}
int main() {
std::thread t(add, 2, 3); // 输出5
t.join();
return 0;
}
未完待续
标签:02,std,thread,do,C++,guard,线程,my From: https://www.cnblogs.com/AEMShana/p/16753770.html