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

标签 c++ multithreading c++11 exception

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

std::thread t( function );
// do some work
// (might throw!)
t.join();

当然,您可以将构造和 join() 之间的所有内容放在 try-catch block 中,但如果您知道要加入或分离,这可能会变得乏味且容易出错不管发生什么。

所以我在想如何围绕它编写最简单的包装器,但同时也支持其他假设类型的线程。例如,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();
}

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

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

最佳答案

如果你想对异步任务进行适当的异常处理,也许你应该使用 std::future 而不是 std::thread。您可以在未来使用 get() 而不是使用 join(),如果 future 抛出异常,则 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;
}

另见:

关于c++ - 使 std::thread 异常安全的最简单方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33307099/

相关文章:

c++ - 什么类型的变量包含 lambda

c++ - GCC 关于 strncpy 使用的误报警告?

c++ - 为什么 string.insert(iterator,char) 连续工作六次而不是七次? (C++)

python - 是否可以并行运行以下网络查询?

multithreading - QT 信号和插槽在单线程应用程序中的直接连接行为

c++ - VS2013中的SFINAE

c++ - 此作业是否创建拷贝?

c++ - 为我的应用程序保存用户数据

c# - 如何模拟C#线程饥饿

c++ - 是否可以在运行时确定对象选择的情况下使用 C++ 对象组合?