这是我的代码:
#include <iostream>
#include <zconf.h>
#include <thread>
class JT {
public:
std::jthread j1;
JT() {
j1 = std::jthread(&JT::init, this, std::stop_token());
}
void init(std::stop_token st={}) {
while (!st.stop_requested()) {
std::cout << "Hello" << std::endl;
sleep(1);
}
std::cout << "Bye" << std::endl;
}
};
void init_2(std::stop_token st = {}) {
while (!st.stop_requested()) {
std::cout << "Hello 2" << std::endl;
sleep(1);
}
std::cout << "Bye 2" << std::endl;
}
int main() {
std::cout << "Start" << std::endl;
JT *jt = new JT();
std::jthread j2(init_2);
sleep(5);
std::cout << "Finish" << std::endl;
}
这是输出:
Start
Hello
Hello 2
Hello
Hello 2
Hello
Hello 2
Hello
Hello 2
Hello
Hello 2
Finish
Bye 2
Hello
问题是我可以得到Bye 2
消息,但不能得到Bye
消息。
我知道传递的stop_token
变量会导致这个问题,但我不知道如何将它传递给另一个成员函数中的成员函数。
如果我正确地理解了这个问题(我的理解是,对于std::jthread(&JT::init, this)
jthread想要调用JT::init(std::stop_token st, this)
,这是不起作用的(,您可能想要使用std::bind_front
来给它一个起作用的Callable。例如
JT() {
j1 = std::jthread(std::bind_front(&JT::init, this));
}
根据有用的注释,我将类代码重写如下:
class JT {
public:
std::jthread j1;
JT() {
j1 = std::jthread(&JT::init, this);
}
void init() {
auto st = j1.get_stop_token();
while (!st.stop_requested()) {
std::cout << "Hello" << std::endl;
sleep(1);
}
std::cout << "Bye" << std::endl;
}
};
您必须通过auto st = j1.get_stop_token();
获得飞行途中的停留时间。
以及修改后的主要功能:
int main() {
std::cout << "Start" << std::endl;
JT *jt = new JT();
// auto jt = std::make_unique<JT>();
std::jthread j2(init_2);
sleep(5);
std::cout << "Finish" << std::endl;
delete jt;
}
您需要直接delete
类对象,或者使用RAII(类似于智能指针(。
在线程构造过程中,JT::init函数必须接收std::stop_token作为参数。您可以使用std::bind
j1 = std::jthread{ std::bind(&JT::init, this, std::placeholders::_1) };
或者,更简单地说,如@Hasturkun答案中的std::bind_front
。
注意在如下构造线程后获得std::stop_token
会导致竞争条件,因为行j1 = std::jthread(&JT::init, this);
涉及构造函数和移动运算符,第二个运算符与行auto st = j1.get_stop_token();
一致,如下所示:
#include <thread>
#include <iostream>
using namespace std::chrono_literals;
class JT {
public:
std::jthread j1;
JT() {
j1 = std::jthread(&JT::init, this);
}
~JT() {
j1.request_stop();
j1.join();
}
void init() {
auto st = j1.get_stop_token();
while (!st.stop_requested()) {
std::this_thread::sleep_for(1ms);
std::cout << "Hello" << std::endl;
}
std::cout << "Bye" << std::endl;
}
};
int main() {
std::cout << "Start" << std::endl;
for (int i = 0; i < 1000; i++) {
JT jt;
std::this_thread::sleep_for(5ms);
}
}
结果是:
Start
Hello
Bye
Hello
Bye
Hello
Hello
Hello
Hello
Hello
Hello
....
节目永远不会结束。我已经用gcc 12.1.0和msvc(VS 2019 16.11.5(进行了发布测试。
这可以通过使用构造函数初始值设定项列表来修复,该列表不会调用移动运算符:
JT() : j1(std::jthread(&JT::init, this)) {
}