thread_guard vs scoped_thread
thread_guard vs scoped_thread
在书中
《C++ Concurrency In Action》作者:Anthony Williams
你可以找到以下两个代码片段(我引入了一些轻微的修改):
片段 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 的优势在哪里(如果存在的话)?
这两种类型都旨在阻止销毁(例如范围退出),直到线程完成。区别在于thread
对象的所有权。
thread_guard
并不拥有thread
本身;可能有多个thread_guard
在同一thread
上等待。这也意味着只要任何thread_guard
引用thread
对象,它就必须处于活动状态。如果在销毁thread_guard
对象时引用的线程已联接,则它不会阻塞或产生错误(而不是仅在不可联接的线程上调用join
)。
另一方面,scoped_thread
拥有thread
实例的所有权,因此也控制其生存期。每当您想拥有要等待的线程时,您都可以使用它,例如作为数据成员。
最终,你使用哪一个是一个语义问题:你是想等待别人拥有的线程(那么你还必须确保没有生命周期问题),还是你想要一个thread
对象,当它被破坏时阻塞,而不必先join
它。
就功能而言,这两种实现都能够服务器的目的,我在这两个实现中看到的唯一区别是,Snippet 2
可以同时接受lvalue(glvalue)
和rvalue(prvalue)
但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;}
但是snippet 2
实现将正常工作。
- 在std::thread中,joinable()然后join()线程安全吗
- <Windows>为什么 std::thread::native_handle 返回类型为"long long unsigned int"的值,而不是 void*(又名 HANDLE)?
- 分离一个静态常量 std::thread?
- 尝试使用 std::vector<std::thread时出现静态断言失败错误>
- 使用 thread 类在 C++ 中构造线程的动态数组时出错
- 当指向对象的指针作为参数传递给 std::thread 时,内存可见性
- 如何从 std::thread 返回值
- 在C++中使用并行化的预期速度是多少(不是 OpenMp,而是 <thread>)
- 将 std::thread by 值推送到列表中
- 转发变量参数列表以模拟 std::thread
- 嵌入式设备 -> std::thread -> FreeRTOS?
- 对 'std::thread::_M_start_thread CMake 的未定义引用进行基准测试
- std::thread 增加 DLL 引用计数,从而防止卸载 DLL
- 如何防止 std::thread 在 QT 中冻结 GUI?
- 对带有唯一指针的 std::thread 使用类成员函数时出现编译错误
- C++ - Thread Pool
- 为什么参数在构造 std::thread 时移动两次
- std::thread::_Invoker 使用线程编程时出错
- 在线程 A 中创建一个 std::thread 对象,在线程 B 中连接
- 为什么编译器抱怨 std::thread 参数在转换为右值后必须是可调用的?