在书中
Anthony Williams的“ C ++并发性”
您可以找到以下两个代码段(我进行了一些小的修改):
代码段1:
class thread_guard
{
std::thread& t;
public:
explicit thread_guard(std::thread& t_): t(t_){}
~thread_guard()
{
if(t.joinable())
{
t.join();
}
}
thread_guard(thread_guard const&)=delete;
thread_guard& operator=(thread_guard const&)=delete;
};
void my_func()
{
for(int j = 0; j < 1000; ++j)
{
cout << "\n " << j;
}
}
void f()
{
std::thread t1(my_func);
thread_guard g(t1);
do_something_in_current_thread();
}
int main()
{
f();
return 0;
}
继续,您可以找到
代码段2:
class scoped_thread
{
std::thread t;
public:
explicit scoped_thread(std::thread t_): t(std::move(t_))
{
if(!t.joinable())
throw std::logic_error(“No thread”);
}
~scoped_thread()
{
t.join();
}
scoped_thread(scoped_thread const&)=delete;
scoped_thread& operator=(scoped_thread const&)=delete;
};
void my_func()
{
for(int j = 0; j < 1000; ++j)
{
cout << "\n " << j;
}
}
void f()
{
scoped_thread st1(thread(my_func));
thread t2(my_func);
scoped_thread st2(move(t2));
do_something_in_current_thread();
}
int main()
{
f();
return 0;
}
我不确定我是否真的能体会到这两个摘要之间的真正区别。
我能看到的唯一区别是,在代码段1中,thread_guard
的实例不拥有线程t1
的所有权(与scoped_thread
对象不同),因此它可能是可能调用t1.join()
,但这在执行~thread_guard()
时不是问题。
那么:片段2的优势在哪里(如果存在)?
答案 0 :(得分:5)
这两种类型都是为了阻止破坏(例如作用域退出)直到线程完成为止。区别在于thread
对象的所有权。
thread_guard
本身并不拥有thread
;在同一thread_guard
上可能有多个thread
等待。这也意味着thread
对象必须是活动的,只要任何thread_guard
引用它。如果在thread_guard
对象被销毁时引用的线程已经被连接,则它不会阻塞或产生错误(与仅在不可连接的线程上调用join
相对)。>
另一方面,
scoped_thread
拥有thread
实例的所有权,因此也可以控制其生存期。每当您想拥有要等待的线程时,例如在作为数据成员。
最终,您使用的是一个语义问题:您要等待别人拥有的线程(然后还必须确保没有生命周期问题),还是要使用{{1} }对象在销毁时会阻塞,而无需首先thread
。
答案 1 :(得分:0)
就功能而言,这两个实现都可以满足目的,我在这两个实现中唯一看到的区别是,Snippet 2
可以接受lvalue(glvalue)
和rvalue(prvalue)
,但是{ {1}}无法接受Snippet 1
作为构造函数参数。例如,考虑以下代码,
rvalue(prvalue)
现在,如果您编译此代码,则编译将产生以下错误,
std::thread getThread()
{
return std::thread([](){ std::cout<< __PRETTY_FUNCTION__<< std::endl;});
}
int main( int , char *[])
{
thread_guard g( getThread());
return 0;
}
但是 error: cannot bind non-const lvalue reference of type ‘std::thread&’ to an rvalue of type ‘std::remove_reference<std::thread&>::type’ {aka ‘std::thread’}
explicit thread_guard(std::thread _t): t(std::move( _t)){ std::cout<< __PRETTY_FUNCTION__<< std::endl;}
实现会很好。