什么是通过外部信号停止 std::thread 的有效方法
What is a valid way to stop a std::thread by an external signal?
不符合设计工作的代码,请解释我这里有什么问题(代码简化以使其更具可读性(。
shm_server server;
std::thread s{server};
// some work...
std::cout << "press any key to stop the server";
_getch();
server.stop();
s.join();
看起来我为类的另一个副本调用了一个stop
方法shm_server
。因为stop()
只将std::atomic_bool done;
(shm_server
成员(设置为 true
但我看到线程函数(这是shm_server
的operator()
(仍然看到done
等于 false
.
std::thread
只有移动结构器?
在这种典型情况下,如何正确地向服务器发送信号?
class shm_server {
std::atomic_bool done;
public:
shm_server() : done{false} {}
shm_server(shm_server& ) : done{false} {}
void operator()() {
while (!done) {
//...
}
}
void stop() {
done = true;
}
};
你以某种方式通过使shm_server
可复制而射中了自己的脚。我相信你这样做是为了摆脱编译器错误,而不是因为该类上的复制语义特别有用。我建议您再次删除该构造函数。如果你真的想要复制语义,让构造函数通过引用const
来获取其参数。
class shm_server // cannot copy or move
{
std::atomic_bool done_ {};
public:
void
operator()()
{
this->run();
}
void
run()
{
using namespace std::chrono_literals;
while (!this->done_.load())
{
std::clog << std::this_thread::get_id() << " working..." << std::endl;
std::this_thread::sleep_for(1ms);
}
}
void
stop()
{
this->done_.store(true);
}
};
为了方便起见,我将调用运算符的逻辑分解到命名函数中。您不需要这样做,但我稍后将在示例中使用它。
现在我们必须以某种方式使 run
成员函数在其自己的线程上执行。如果你写
shm_server server {};
std::thread worker {server}; // won't compile
编译器不会让你这样做,因为它 - 正如你自己推测的那样 - 会尝试复制不可复制的server
对象。
@Ben Voigt建议将server
对象包装到一个std::reference_wrapper
中,该是一个行为类似于引用的对象。
shm_server server {};
std::thread worker {std::ref(server)};
这将按预期工作,并有效地传递指向std::thread
构造函数的指针,而不是实际的server
对象。
但是,我发现这不是这里最直接的解决方案。您真正想做的是在不同的线程上运行server
的成员函数。而std::thread
的构造函数可以让你做到这一点。
shm_server server {};
std::thread worker {&shm_server::run, &server};
在这里,我将 run
成员函数的地址和指向 server
对象的指针(将作为隐式this
指针传递(作为参数传递。我引入了run
函数,因为语法可能不那么烦人。您也可以直接传递呼叫接线员的地址。
shm_server server {};
std::thread worker {&shm_server::operator(), &server};
这是一个完整的示例。
int
main()
{
using namespace std::chrono_literals;
std::clog << std::this_thread::get_id() << " starting up" << std::endl;
shm_server server {};
std::thread worker {&shm_server::operator(), &server};
//std::thread worker {std::ref(server)}; // same effect
//std::thread worker {&shm_server::run, &server}; // same effect
std::this_thread::sleep_for(10ms);
server.stop();
worker.join();
std::clog << std::this_thread::get_id() << " good bye" << std::endl;
}
可能的输出:
140435324311360 starting up
140435306977024 working...
140435306977024 working...
140435306977024 working...
140435306977024 working...
140435306977024 working...
140435306977024 working...
140435306977024 working...
140435306977024 working...
140435306977024 working...
140435306977024 working...
140435324311360 good bye
如果您认为 shm_server
只有在其自己的线程上运行时才有用,您还可以为其提供数据成员std::thread
,并使其构造函数(或专用的 start
成员函数,如果您愿意(启动,其析构函数加入线程。
#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>
class shm_server
{
std::atomic_bool done_ {};
std::thread worker_ {};
public:
shm_server()
{
this->worker_ = std::thread {&shm_server::run_, this};
}
~shm_server()
{
this->done_.store(true);
if (this->worker_.joinable())
this->worker_.join();
}
private:
void
run_()
{
using namespace std::chrono_literals;
while (!this->done_.load())
{
std::clog << std::this_thread::get_id() << " working..." << std::endl;
std::this_thread::sleep_for(1ms);
}
}
};
int
main()
{
using namespace std::chrono_literals;
std::clog << std::this_thread::get_id() << " starting up" << std::endl;
{
shm_server server {};
std::this_thread::sleep_for(10ms);
}
std::clog << std::this_thread::get_id() << " good bye" << std::endl;
}
- 在std::thread中,joinable()然后join()线程安全吗
- 分离一个静态常量 std::thread?
- 当指向对象的指针作为参数传递给 std::thread 时,内存可见性
- 如何从 std::thread 返回值
- 将 std::thread by 值推送到列表中
- 转发变量参数列表以模拟 std::thread
- 对 'std::thread::_M_start_thread CMake 的未定义引用进行基准测试
- std::thread 增加 DLL 引用计数,从而防止卸载 DLL
- 如何防止 std::thread 在 QT 中冻结 GUI?
- 对带有唯一指针的 std::thread 使用类成员函数时出现编译错误
- 为什么参数在构造 std::thread 时移动两次
- std::thread::_Invoker 使用线程编程时出错
- 在线程 A 中创建一个 std::thread 对象,在线程 B 中连接
- 为什么编译器抱怨 std::thread 参数在转换为右值后必须是可调用的?
- ZeroMQ 在使用 std::thread 创建工作线程时崩溃
- 在没有复制构造函数的对象的成员函数中启动 std::thread
- CLang:在 std::thread 中运行函数会导致结构创建BAD_ACCESS
- 调用以CWinThread为基的类运算符()的std::thread失败
- 如何通过std::thread生成多个线程
- std::future::get()或std::future::wait()是std::thread::join()的替