Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I declare an std::thread anonymously?

Consider the following short program:

#include <thread>

int Foo() {
while (1);
}

int main(){
    std::thread t(Foo);
    std::thread s(Foo);

    // (std::thread(Foo));

    t.join();
}

This compiles and runs (forever), with

g++ -Wl,--no-as-needed DoubleBufferTest.cc -o DoubleBufferTest -std=c++0x -pthread

In the commented out line, I am trying to use the technique described here to declare a new thread anonymously. However, when that line is commented back in, I can compile but running gives the following error:

terminate called without an active exception            
Aborted (core dumped)                                   

How can I correctly declare a thread anonymously?

Note, I am on g++ 4.4.7.

like image 257
merlin2011 Avatar asked Jan 17 '14 23:01

merlin2011


3 Answers

You can do it like this:

std::thread(Foo).detach();
like image 86
Howard Hinnant Avatar answered Oct 01 '22 23:10

Howard Hinnant


std::thread's destructor will call std::terminate if the thread has not been joined or detached.

So unfortunately you cannot create an anonymous thread object like this - you need a reference to the thread object in order to call either join() or detach().

Scott Meyers gave a talk at Going Native 2013 where he created an RAII class that wraps a thread and calls join in the destructor. You could do something similar:

class ThreadRAII {
public:
  ThreadRAII(std::thread&& thread): t(std::move(thread)) {}
  ~ThreadRAII() { if (t.joinable()) { t.join(); }

private:
  std::thread t;
};

See his blog post or talk for more info.

You could use it like this

(ThreadRAII(std::thread(Foo)));

However, the only reason you'd want to create a thread in this way is if you don't care when (or if) it ends, so in this case, join doesn't make much sense. You should modify the destructor to detach instead:

~ThreadRAII() { if (t.joinable()) { t.detach(); }

As suggested in the comments, you could make it even easier to use by perfect forwarding to an internal thread on construction:

class ThreadRAII2 {
public:    

    template <typename Func, typename ...Args>
    explicit ThreadRAII2(Func&& func, Args&&... args) :
        t(func, std::forward<Args>(args)...) {  }

    ~ThreadRAII2() { 
        if (t.joinable()) t.detach(); 
    }
private:
    std::thread t;
};

Then you can use it just like you originally wanted to, no detach necessary:

(ThreadRAII2(Foo));

Or, if Foo takes arguments (for example Foo(int)):

(ThreadRAII2(Foo, 42));
like image 36
zmb Avatar answered Oct 02 '22 00:10

zmb


I don't think this (the technique you are referring to) is possible with threads.

Take a look here;

30.3.1.3 thread destructor [thread.thread.destr]

~thread();

If joinable() then terminate(), otherwise no effects. [ Note: Either implicitly detaching or joining a joinable() thread in its destructor could result in difficult to debug correctness (for detach) or performance (for join) bugs encountered only when an exception is raised. Thus the programmer must ensure that the destructor is never executed while the thread is still joinable. — end note ]

Basically the temporary anonymous object (i.e. thread) you are creating is destructed right when execution continues to the next line which violates the above rule.

like image 25
ben Avatar answered Oct 01 '22 23:10

ben