7

I want to create a C++ class with a thread doing some work once a minute.

First, may I define a thread as a variable member?

class my_class
{
public:
    my_class()
        : my_thread_(task, this)
    {
    }

    ~my_class()
    {
        done_ = true;
    }

    void run()
    {
        while(!done_)
        {
            ...do work in the thread...
        }
    }

private:
    static task(my_class * ptr)
    {
        ptr->run();
    }

    std::thread          my_thread_;
    std::atomic<bool>    done_ = false;
};

Second, may I instead use a smart pointer with the thread in it?

class my_class
{
public:
    ~my_class()
    {
        done_ = true;
    }

    void init()
    {
        my_thread_.reset(new std::thread(task, this));
    }

    void run()
    {
        while(!done_)
        {
            ...do work in the thread...
        }
    }

private:
    static task(my_class * ptr)
    {
        ptr->run();
    }

    std::unique_ptr<std::thread>    my_thread_;
    std::atomic<bool>               done_ = false;
};

It seems to me that I need to join with the child thread before it can be destroyed, but I am wondering whether the destructor of std::thread knows to do that safely.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156

3 Answers3

5

You can put std::threads where ever you want, they are not special. Destroying thread handles is problematic. You can implicitly detach, implicitly kill or implicitly join and every option is bad. std::~thread (usually) just kills the whole program. To prevent that join or detach it.
Since you seem to want to implicitly join you may want to use std::async (probably with the std::launch::async policy) to launch your threads. It returns an std::future who's destructor implicitly joins.

nwp
  • 9,623
  • 5
  • 38
  • 68
  • Only I want my process to always be running in the background and `std::async`, from what I understand, is not 100% guaranteed to create a trhead to run the task. It could do it in the front thread. But I really need to separate tasks running in parallel. – Alexis Wilke Jun 05 '16 at 21:08
  • @AlexisWilke That's why I commented about the `std::launch::async` policy which forces `std::async` to create a thread. If you don't care about synchronization and just want a thread running use `std::thread` and call `.detach()` on it. – nwp Jun 05 '16 at 21:19
4

it's possible to create std::unique_ptr<std::thread>. It will call std::thread destructor, when scope of unique_ptr will end. Remember that calling std::thread destructor is not terminating running thready gently, but by std::terminate. To end std::thread normally, you have to run .join() on std::thread object.

paweldac
  • 1,144
  • 6
  • 11
3

According to cppreference.com,

A thread object does not have an associated thread (and is safe to destroy) after

  • it was default-constructed
  • it was moved from
  • join() has been called
  • detach() has been called

So if you define the thread as a member variable and write your destructor like this:

~my_class()
{
    done_ = true;
    my_thread_.join();
}

everything is fine, because it is guaranteed by the standard that the std::thread destructor will be called only after the my_class destructor, see this Q/A.

Community
  • 1
  • 1
alain
  • 11,939
  • 2
  • 31
  • 51