c++multithreadingclassinvokemember

The thread callback doesn’t seem run when I construct `std::jthread` as a local variable inside a method, why?


I'm struggling to re-learn C++ and I'm playing around with jthread at the moment.
I seem to have got things working when calling a class member function that I want on its own thread.
However, the function never actually seems to get called. I can't work out what I'm missing here.
If someone can point out my inevitably "learner's" error, I'd be really grateful.

// includes and directives

#include <iostream>
#include <thread>
#include <functional>
#include <chrono>

// a class for testing stuff

class A {
private:
    int updates{ 0 }; // something to count on
    int tick{ 1000 }; // tick time set to 1000ms initially

public:
    void set_tick(int t) {
        tick = (t<1?1:t); // sanity check and set tick time
    }

    int get_updates() {
        return updates; // I did how many?
    }

    void update(std::stop_token st) {
        while (!st.stop_requested()) { // stop if they say stop
            updates++; // count this as an update
            std::cout << "Performing update" << updates << "\n"; // visually indicate something happened
            std::this_thread::sleep_for(std::chrono::milliseconds(tick)); // wait for tick time before doing it all again
        }
    }

    void start() { // start a ticking function
        std::cout << "Starting update thread\n"; // tell someone responsible that it's started
        std::jthread thr_A(std::bind_front(&A::update, this)); // start the parallel process fucntion in this class
    }
};

// main thing

int main()
{
    std::cout << "Start main thread\n"; // say that I'm starting up 
    A a; // make me a sandwich
    a.set_tick(10); // really fast(ish)
    a.start(); // go on, get on with it
    std::this_thread::sleep_for(std::chrono::milliseconds(10000)); // wait until sandwich ready
    std::cout << "Wake main thread and terminate\n"; // sandwich is ready, time to eat
}


Solution

  • thr_A is defined as a local variable in start().
    It is destructed when it gets out of scope - i.e. when start() returns.
    Since it is a jthread, upon destruction it is requested to stop and then joined.
    Since start() returns right after launching thr_A, the thread barely gets a chance to actually run.

    A possible solution can be to add thr_A as a member of class A. This means its destructor will be invoked only when your a is destroyed - in your case: when main() exits.

    This way the thread will execute all the logic you expect.

    Live demo

    Note: in the live demo I reduced the sleep_for in main() to avoid Godbolt timeout.