gpt4 book ai didi

c++ - 通过外部信号停止 std::thread 的有效方法是什么?

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:08:40 28 4
gpt4 key购买 nike

这是一段无法按设计工作的代码,请向我解释这里出了什么问题(简化代码以使其更具可读性)。

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 done; (shm_server 成员)设置为 true 但我看到了线程函数(这是 shm_serveroperator())仍然看到 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 Voigtsuggestedserver 对象包装到 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;
}

关于c++ - 通过外部信号停止 std::thread 的有效方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34665619/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com