这是一个不按设计工作的代码请解释我这里有什么问题(简化代码以使其更易读)。
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
,但我看到线程函数(这是operator()
的{{1}})仍然看到shm_server
等于done
。
false
只移动了构造函数吗?
在这种典型情况下如何正确地向服务器发送信号?
std::thread
答案 0 :(得分:2)
你可以通过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有suggested将server
对象包装到std::reference_wrapper
中,{{3}}是一个行为类似于引用的对象。
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
作为数据成员并拥有它的构造函数(或者一个专用的{{1}成员函数,如果你愿意)start和它的析构函数加入线程。
start