C++11: std::threads managed by a designated class

Recently I have noticed an unobvious problem that may appear when using std::threads as class fields. I believe it is more than likely to meet if one is not careful enough when implementing C++ classes, due to it’s tricky nature. Also, its solution provides an elegant example of what has to be considered when working with threads in object-oriented C++, therefore I decided to share it.

Consider a scenario where we would like to implement a class that represents a particular thread activity. We would like it to:

  • start a new thread it manages when an instance is constructed
  • stop it when it is destructed

I will present the obvious implementation, explain the problem with it, and describe how to deal with it.

So the outline would certainly look like this:

#include <thread>
class MyClass{
public:
    MyClass();
    ~MyClass();
private:
    std::thread the_thread;
    bool stop_thread = false; // Super simple thread stopping.
    void ThreadMain();
};

Okay, but the default std::thread constructor is pretty pointless here, it “Creates new thread object which does not represent a thread“. So a pretty obvious solution is to explicitly use another constructor, which will actually launch the thread:

the_thread(&MyClass::ThreadMain, this)

Then we can implement the thread routines within ThreadMain method.  The destructor would take care of stopping the thread gracefully and waiting for it to terminate.

#include <thread>
#include <chrono>
class MyClass{
public:
    MyClass() : the_thread(&MyClass::ThreadMain, this) {}
    ~MyClass(){
         stop_thread = true;
         the_thread.join();
    }
private:
    std::thread the_thread;
    bool stop_thread = false; // Super simple thread stopping.
    void ThreadMain(){
        while(!stop_thread){
            // Do something useful, e.g:
            std::this_thread::sleep_for( std::chrono::seconds(1) );
        }
    }
};

This seems like an elegantly implemented class managing the thread. It will even [seem to] work correctly!

But there is a critical problem with it.

The new thread will start running as soon as it is constructed. It will not wait for the constructor to finish its work (why should it?). It may, and sometimes, at random, it will, leading you into a false sense of security and correctness. It will not even wait for other class fields to be constructed. It has the right to cause crash when accessing stop_thread. And what if your class has other fields that are not atomic? The thread can start using uninitialized objects, problems guaranteed.

One possible solution would be to have the constructor notify the thread when it is safe to start, from within its body. This might be accomplished with an atomic or with a conditional variable. Keep in mind that it would need to be constructed before the std::thread, so that it is ready to use when the thread starts (so the order of construction really does matter!).

This might work in case of the code I use for demonstration. But in general case this will do no good. Imagine use a hierarchy of polymorphic thread-managing classes; imagine that ThreadMain is virtual. In such scenario its addresses is derived from the vtable. But the vtable pointer is initialized after the block of the constructor! This means the starting thread would start from calling a wrong function, leading to a variety of confusing behavior. The idea of notifying it when to start won’t help here.

A universal solution would be to prepare then class in two steps.

  • First, construct it.
  • When it is ready to use, call Start() which will actually launch the thread.

Like this:

MyClass instance;
instance.Start();

So we will need to start with no thread running, and construct it dynamically when Start is called. My first thought was:

class MyClass{
public:
    MyClass(){}
    ~MyClass(){/****/}
    void Start(){
        the_thread = new std::thread(&MyClass::ThreadMain,this);
    }
private:
    std::thread* the_thread; // Or you could use std::unique_ptr<>.
    /****/
};

 

But this just feels wrong. Pointers? Seriously, are we forced to manually manage memory?

No. std::thread is movable! So we can use that boring default std::thread constructor (not that pointless, right?) to construct it at the beginning, and then, when Start() is called, we will substitute it with an actual running thread! Like that:

class MyClass{
public:
    /* Explicitly using the default constructor to
     * underline the fact that it does get called */
    MyClass() : the_thread() {}
    ~MyClass(){
        stop_thread = true;
        if(the_thread.joinable()) the_thread.join();
    }
    void Start(){
        // This will start the thread. Notice move semantics!
        the_thread = std::thread(&MyClass::ThreadMain,this);
    }
private:
    std::thread the_thread;
    /****/
};

Now this is both safe and elegant.

This scenario has taught me to stay vigilant when mixing asynchronous execution with stuff that C++ does on the lower levels. I do hope that it has opened your eyes too, or that at least you will remember it as a simple yet interesting case!

 

Advertisement

28 Responses to “C++11: std::threads managed by a designated class”

  1. Fabien R Says:

    Clear and helpful.

  2. Adryan Kobayashi Says:

    Thank for this very helpful exemple. I was looking for an implementation which had exactly the same behavior.

  3. Kiran Says:

    Thanks. This helps. Assume a scenario like thread is blocking on some call and then while(!stop_thread) won’t be checked, is there any way to exit the thread ? As the join also will block then.

    • Rafał Cieślak Says:

      The way I see it is that if you want a thread to be stoppable by breaking the loop this way, then you never use any calls that may block for a long period of time. Most blocking calls, however, have a non-blocking variant, or can be used with a custom timeout (which causes the call to return in case it’s blocking for too long). In the rare case when no such version is available, and there is no other way avoid a blocking function, you can use OS mechanisms to help you manage such threads. For example, on *NIX system you might send a signal to a blocked thread, and have the signal handler react accordingly. This might be not an easy-to-implement approach, though.

  4. psychogears Says:

    Great article. Exactly what I was looking for. Most of G’s search results for “c++ thread as class member” discuss how to launch a member method as a separate thread… not so much how to do it safely, though. Thanks for this.

  5. c++dude Says:

    Alternatively simply have the constructor call a private Start() method in the constructor body.

    • Rafał Cieślak Says:

      Still unsafe. This might be okay in some cases when no polymorphism is involved, but the vtable is initialised *after* the constructor body. So starting the thread before the constructor has completed it’s work may result in the thread starting with a wrong, or even invalid function.

      • J Says:

        Something here is incorrect.
        No matter if the vtable is filled AFTER or BEFORE constructor’s body, calling virtual functions from constructors/destructors is not forbidden. One just calls current classes’ method:
        https://isocpp.org/wiki/faq/strange-inheritance#calling-virtuals-from-ctors

        Nonetheless, solution proposed by c++dude is unsafe as derived class may need to wait with starting their thread with its initialization. Still possible to be implemented with simple boolean flag as constuctor’s parameter.

  6. Avinash Sridharan Says:

    For the move copy assignment operator to kick in, don’t you need to use the std::move operator?? I think your code should be
    the_thread = std::move(std::thread(&MyClass::ThreadMain,this));
    instead of
    the_thread = std::thread(&MyClass::ThreadMain,this);

    • Rafał Cieślak Says:

      Thanks for pointing that out, but in this case std::move is not needed. This is because std::thread(&MyClass::ThreadMain,this) is an r-value here. Therefore a move assignment will be used to perform this instruction. I would need to use std::move if the thread being moved was an x-value, for example: if it already existed as an instance stored in a variable.
      This makes a lot of sense, if you look at it this way: the std::thread created here is a temporary object which is constructed only in order to describe how we want to change the_thread. So that temporary std::thread does not exist on it’s own, and the compiler can move it instead of simply copying – that effectively invalidates the temporary object, but it’s fine, because it’s temporary, and not referenced anywhere else. Such behaviour is obviously more efficient, and because it will never do any harm, it is included in the standard.

      • Avinash Sridharan Says:

        Agreed. Scratch my comment. Still new to understanding r-value references and move assignment operators. In this case as Rafal pointed out the RHS is r-value so compiler will automatically take the move-assignment operator instead of the copy assignment operator.

  7. Arun Chandrasekaran Says:

    stop_thread is not thread safe. You should consider using “std::atomic_bool stop_thread;”.

  8. Fun with std::threads! | socapex Says:

    […] Here is a good blog with some more information about the subject. In the end, I do not see why I wouldn’t use the thread-object analogy, unless I am dealing with very simple things, or a single temporary thread spawned. Other than that it “just makes sense”. […]

  9. Fleshbits Says:

    What is the parent thread (main) going to wait on, when it needs to wait for all these child threads to exit which are owned by this class?

    • Rafał Cieślak Says:

      You can add an explicit “Join” method to the container class which calls std::thread::join().

      • Fleshbits Says:

        That creates UDB, as you cannot programmatically enforce that only the parent thread calls join. You’d also have to create some mechanism for the parent thread to wait on _all_ child threads by calling join one at a time, which would most likely be some collection of these classes in the parent, which leads to the problem I am experiencing where you cannot iterate while handling a signal, as the iterators are not guaranteed.

        The standard needs a mechanism to interrupt/kill threads, and to send events back to the parent when they exit, as far as I can tell. I’d love to see an example of main spawning off many threads via a class for each, and signalling them all to exit their loops, then successfully waiting on them to join. While I can compile a program to do it that runs, it doesn’t do so without the UDB that is described in std::thread documentation.

      • Rafał Cieślak Says:

        I really hope that the std::async and std::future improvements that are planned for C++17 will include such mechanisms.
        Meanwhile, please have a look at http://en.cppreference.com/w/cpp/thread/notify_all_at_thread_exit

      • Fleshbits Says:

        I think the comment board here only goes two deep. Won’t let me reply to your last.
        As far as using notify_)all_thread_exit , detach, and a condition variable, that would allow the parent to wait on one child, but I don’t see how I could use that to wait on multiple children, without say some collection of condition variables and mutexes. Isn’t there a way to use on condition variable to signal the exit of multiple/all child threads has occurred? The fellas on comp.lang.C++ hinted at using a condition variable too, but I could not get an example out of ’em that included usage of a class wrapper.

  10. freeflyclone Says:

    Thank you so much for this. Exactly what I needed!

  11. Yann Suissa Says:

    >>Thank you so much for this. Exactly what I needed!

    exactly the same here! Thanks!

  12. confused Says:

    Is there a way to put MyClass instance into vector? It would be damn perfect solution then, but i’m unable to make it work properly :S

  13. Origami Bulldoser (xeche) Says:

    If the class suggested in this solution is instantiated as a global, won’t it crash because the global is destroyed after main exits?

  14. ktchow1 Says:

    very detailed. thank you

  15. ilya1725 Says:

    Thank you for a great example and explanation.
    Do you mind expanding on the topic a bit? Specifically in terms of local thread’s memory and how it can access the object it belong to. If I have some synchronization constructs between the main thread and `ThreadMain`. Does `ThreadMain` have full access to the `MyClass` object or I will have to pass pointer to `this` as the parameter?

  16. kwrettinger Says:

    Very helpful, thank you!

  17. Stan le punk Says:

    HEllo, your exemple is very good starting point for me, that’s work perfectly with .join() But you know if it’s possible to that with threas.detach ? Because when I try nothing happen. If you have a time my code is here https://github.com/StanLepunK/CPP_basics/blob/master/THREAD/good_thread_detach.cpp

    And thanks again for this article.

  18. James Says:

    Very good writing! But, it can still run into problems. This solution avoids running the thread on a half constructed object, but it has the exact same issue on the destructor. Once it enters the base class’s destructor (before the_thread.join() is called), the derived class’ destructor is already called, and thus, if the thread is still running, it runs on a half-destructed object, it is an UB. You may or may not run into issue, but once you encountered a problem, it’s going to be very confusing and very hard to debug.

    In fact, the root cause of the problem is a “circular dependency”, MyClass consists the_thread, and the_thread binds to the instance of MyClass. To break this circular dependency, you need define your service class as a “runnable” with all your biz logic in it, and have a separate thread class that responsible for running the “runnable” service.

    There are many ways to do it, and here is one of them:

    class MyService {
    public:
    virtual ~MyService() = default;
    virtual void run() = 0;
    };

    class MyFooService : public MyService {
    public:
    void run() {
    std::cout << "My Foo …" << std::endl;
    }
    };

    class MyServiceRunner {
    public:
    MyServiceRunner(std::unique_ptr service) : service_(std::move(service)) { }
    ~MyServiceRunner() { stop(); }
    void start() { thread_ = std::thread(&MyService::run, service_.get()); }
    void stop() { if (thread_.joinable()) thread_.join(); }
    private:
    std::unique_ptr service_;
    std::thread thread_;
    };

    int main(){
    std::unique_ptr s = std::make_unique();
    MyServiceRunner runner(std::move(s));
    runner.start();
    return 0;
    }

    Of course, if you can make MyService final, then you do not need to worry about things we talked about in this post at all.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: