11

考虑以下短程序:

#include <thread>

int Foo() {
while (1);
}

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

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

    t.join();
}

这编译并运行(永远),与

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

在注释掉的行中,我正在尝试使用此处描述的技术来匿名声明一个新线程。但是,当该行被重新注释时,我可以编译但运行会出现以下错误:

terminate called without an active exception            
Aborted (core dumped)                                   

我怎样才能正确地匿名声明一个线程?

注意,我在g++ 4.4.7

4

3 回答 3

12

你可以这样做:

std::thread(Foo).detach();
于 2014-01-17T23:41:10.757 回答
12

std::threadstd::terminate如果线程尚未加入或分离,则将调用 的析构函数。

所以不幸的是,您不能像这样创建匿名线程对象 - 您需要对该thread对象的引用才能调用join()detach()

Scott Meyers 在 Going Native 2013 上发表了演讲,他创建了一个 RAII 类,该类包装了一个线程并在析构函数中调用 join。你可以做类似的事情:

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

private:
  std::thread t;
};

请参阅他的博客文章讨论以获取更多信息。

你可以像这样使用它

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

但是,您希望以这种方式创建线程的唯一原因是您是否不在乎它何时(或是否)结束,因此在这种情况下,join 没有多大意义。您应该修改析构函数以分离:

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

正如评论中所建议的,您可以通过完美转发到构造中的内部线程来使其更易于使用:

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;
};

然后你可以像你最初想要的那样使用它,不需要分离:

(ThreadRAII2(Foo));

或者,如果Foo需要参数(例如Foo(int)):

(ThreadRAII2(Foo, 42));
于 2014-01-17T23:35:55.150 回答
4

我认为线程不可能实现这一点(您所指的技术)。

看看这里;

30.3.1.3 线程析构函数[thread.thread.destr]

〜线程();

如果 joinable() 则终止(),否则无效。[ 注意:在其析构函数中隐式分离或加入 joinable() 线程可能导致难以调试正确性(分离)或性能(加入)错误,仅在引发异常时遇到。因此,程序员必须确保在线程仍可连接时永远不会执行析构函数。——尾注]

基本上,当执行继续到违反上述规则的下一行时,您正在创建的临时匿名对象(即线程)就会被破坏。

于 2014-01-17T23:35:19.990 回答