这是一个不按设计工作的代码请解释我这里有什么问题(简化代码使其更具可读性).
shm_server server;
std::thread s{server};
// some work...
std::cout << "press any key to stop the server";
_getch();
server.stop();
s.join();
看起来我为另一个shm_server类副本调用了stop方法.
因为stop()只设置std :: atomic_bool; (shm_server成员)为true但我看到线程函数(这是shm_server的operator())仍然看到完成等于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
编译器不会让你这样做 – 正如你自己猜测的那样 – 会尝试复制不可复制的服务器对象.
@Ben Voigt具有suggested以将服务器对象包装到std::reference_wrapper
中,该对象的行为类似于引用.
shm_server server {};
std::thread worker {std::ref(server)};
这按预期工作,并有效地将指针传递给std :: thread构造函数,而不是实际的服务器对象.
但是,我发现这不是最直接的解决方案.您真正想要做的是在不同的线程上运行服务器的成员函数.而std :: thread的构造函数可以让你做到这一点.
shm_server server {};
std::thread worker {&shm_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;
}