使std :: thread异常安全的最简单方法

rel*_*dom 3 c++ multithreading exception c++11

std::thread因为析构函数调用,class本质上是异常不安全的std::terminate.

std::thread t( function );
// do some work
// (might throw!)
t.join();
Run Code Online (Sandbox Code Playgroud)

当然,你可以把所有东西放在构造之间和join()try-catch块之间,但如果你知道你想要加入或分离,无论发生什么,这都会变得乏味且容易出错.

所以我在想如何围绕它编写最简单的包装器,但这也会支持其他假设类型的线程.例如,boost::thread或者完全不同的东西,只要它有joinable(),join()detach()方法.这是我有多远:

// handles threads safely
// Acts the same as the underlying thread type, except during destruction.
// If joinable, will call join (and block!) during destruction.
// Keep in mind that any exception handling will get delayed because of that;
// it needs to wait for the thread to finish its work first.
template <class UNDERLYING_THREAD = std::thread>
class scoped_thread: public UNDERLYING_THREAD
{
public:
    typedef UNDERLYING_THREAD thread_type;

    using thread_type::thread_type;

    scoped_thread()
            : thread_type() {}

    scoped_thread( scoped_thread && other )
            : thread_type( std::move( other ) ) {}

    scoped_thread & operator = ( scoped_thread && other )
    {
        thread_type & ref = *this;
        ref = std::move( other );
        return *this;
    }

    ~scoped_thread()
    {
        if( thread_type::joinable() )
            thread_type::join();
    }
};

// handles autonomous threads safely
// Acts the same as the underlying thread type, except during destruction.
// If joinable, will call detach during destruction.
// Make sure it doesn't use any scoped resources since the thread can remain
// running after they go out of scope!
template <class UNDERLYING_THREAD = std::thread>
class free_thread
{
    // same except it calls detach();
}
Run Code Online (Sandbox Code Playgroud)

这似乎有效,但我想知道是否有办法避免手动定义构造函数和移动赋值运算符.可能我注意到的最大问题是如果你提供一个带有删除的移动构造函数的类作为模板参数,编译将会失败.

您对如何避免这种情况有什么建议吗?或者这种方法还有其他更大的问题吗?

Dao*_*Wen 5

如果你想对异步任务进行适当的异常处理,也许你应该使用std::future而不是std::thread.join()您将get()在未来使用,而不是使用,如果将来引发异常,get()则会导致相同的异常.

一个简单的例子:

#include <future>
#include <iostream>

int my_future_task(int my_arg) {
    throw std::runtime_error("BAD STUFF!");
    return my_arg;
}

int main(int argc, char* argv[]) {
    auto my_future = std::async(my_future_task, 42);
    try {
        my_future.get();
    }
    catch(std::exception &e) {
        std::cout << "Caught exception: " << e.what() << std::endl;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

也可以看看: