C++ 通过外部信号停止std::线程的有效方法是什么?
这是一个不按设计工作的代码,请解释我这里的错误(代码简化,使其更具可读性)C++ 通过外部信号停止std::线程的有效方法是什么?,c++,multithreading,c++11,C++,Multithreading,C++11,这是一个不按设计工作的代码,请解释我这里的错误(代码简化,使其更具可读性) 通过使shm_服务器可复制,你不知何故把自己的脚撞到了地上。我相信您这样做是为了消除编译器错误,并不是因为该类上的复制语义特别有用。我建议您再次删除该构造函数。如果确实需要复制语义,请让构造函数通过引用const获取其参数 class shm_server // cannot copy or move { std::atomic_bool done_ {}; public: void operator
通过使
shm_服务器
可复制,你不知何故把自己的脚撞到了地上。我相信您这样做是为了消除编译器错误,并不是因为该类上的复制语义特别有用。我建议您再次删除该构造函数。如果确实需要复制语义,请让构造函数通过引用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);
}
};
编译器不会让您这样做,因为它会尝试复制不可复制的server
对象
必须将服务器
对象包装到一个类似于引用的对象中
shm_server server {};
std::thread worker {std::ref(server)};
这会按预期工作,并有效地将指针传递到std::thread
构造函数,而不是实际的服务器
对象
然而,我发现这并不是最直接的解决方案。您真正想要做的是在不同的线程上运行服务器的成员函数。而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;
}
如果您认为一个shm_服务器
只有在它自己的线程上运行时才有用,那么您还可以给它一个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;
}
#包括
#包括
#包括
#包括
类shm_服务器
{
std::原子布尔完成{};
std::线程工作线程{};
公众:
shm_服务器()
{
this->worker=std::thread{&shm\u server::run\uu,this};
}
~shm_server()
{
此->完成存储(true);
如果(此->工作者可接合())
此->worker_u2;.join();
}
私人:
无效的
跑()
{
使用名称空间std::chrono_文本;
而(!this->done_uz.load())
{
std::clog Trystd::threads{std::ref(服务器)}
为避免复制相关:谢谢!std::ref解决方案可为我提供详细解释。是的,我添加了复制ctor,但没有真正分析内部问题,只是看到了复制原子库的问题。在使用std::ref的建议后,我已将其删除为未使用。关于成员传递。我使用了对象本身,而不是r由于某种原因,它看起来比函数传递更清晰,所以实际上,成员传递对于功能来说是可以的。关于服务器内部的线程对象的问题:这种模式更可取吗?有什么优点吗?将线程逻辑封装在服务器类中可以让客户端不必担心它。另一方面,它使设计不够灵活。可能有些客户希望在自己的线程上运行它,或者使用另一个线程库。还要考虑单元可测试性。我不知道什么能很好地适合您的用例。谢谢,封装对我来说更可取,客户希望“创建并忘记”关于服务器对象。理想情况下,服务器应该完全自己管理所有对象
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;
}
#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;
}