c++ std::jthread从另一个成员函数运行成员函数

uyto3xhc  于 2023-02-10  发布在  其他
关注(0)|答案(3)|浏览(201)

下面是我的代码:

#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变量会导致这个问题,但我不知道如何将它传递给另一个成员函数内部的成员函数。

wrrgggsh

wrrgggsh1#

如果我正确理解了这个问题(我的理解是对于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));
}
iqjalb3h

iqjalb3h2#

根据有用的注解,我已经将类代码重写如下:

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();动态获取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(如智能指针)。

q0qdq0h2

q0qdq0h23#

std::stop_token必须在线程构造过程中作为参数由JT::init函数接收。

j1 = std::jthread{ std::bind(&JT::init, this, std::placeholders::_1) };

或者,更简单地说,std::bind_front,如@Hasturkun答案中所示。

    • 注意在构造线程之后获取std::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)测试过了。

相关问题