c++ - 通过加入析构函数来等待异步工作是否安全?

标签 c++ multithreading c++11 thread-safety object-lifetime

假设我有一个可以异步运行一些代码的类,并且该异步代码使用该类实例来执行调用成员函数、读取数据成员等操作。显然,该类实例必须比后台线程长寿,以便那些访问是安全的。在析构函数中加入后台线程就足以保证这一点了吗?例如:

#include <iostream>
#include <thread>

class foo final
{
public:
    foo() = default;

    void bar() {
        std::cout << "Hopefully there's nothing wrong with using " << this << "\n";
    }

    void bar_async() {
        if (!m_thread.joinable()) {
            m_thread = std::thread{&foo::bar, this};
        }
    }

    ~foo() {
        if (m_thread.joinable()) {
            std::cout << "Waiting for " << m_thread.get_id() << "\n";
            m_thread.join();
        }
    }

private:
    std::thread m_thread;
};

int main() {
    foo f;
    f.bar_async();
}

具体来说,我担心 object lifetime rules :

For any object of class types whose destructor is not trivial, lifetime ends when the execution of the destructor begins.

... after the lifetime of an object has ended and before the storage which the object occupied is reused or released, the following uses of the glvalue expression that identifies that object are undefined: ...

  • Access to a non-static data member or a call to a non-static member function.

但对我来说,严格阅读上述内容还意味着直接从 ~foo() 内部调用 this->bar() 是未定义的,这是“显然”并非如此。

最佳答案

cppreference 是对的,但它是在谈论从对象而不是从析构函数内部访问成员。如果我们查看 [class.cdtor]/1,我们会看到

For an object with a non-trivial constructor, referring to any non-static member or base class of the object before the constructor begins execution results in undefined behavior. For an object with a non-trivial destructor, referring to any non-static member or base class of the object after the destructor finishes execution results in undefined behavior.

强调我的

因此,只要我们在析构函数中,我们仍然可以使用成员对象,因为在析构函数的作用域结束之前,它们不会被销毁。

因此,在这里调用线程上的 join 没问题。如果您考虑一下,如果不是,那么如果访问它们引用的互斥量是未定义的行为,那么诸如锁守卫之类的东西将毫无用处。

关于c++ - 通过加入析构函数来等待异步工作是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46181083/

相关文章:

c++11 enable_if 错误 - 模板参数重新声明

.net - 64 位 .net 上 Int32/Int64 操作的线程安全

c++ - 未为使用默认模板参数声明的别名模板指定模板参数时出错

c++ - compare_exchange_weak() 编译错误?

c++ - 如何将数字读入数组直到行尾?

c++ - 这是什么代码?为何起作用? C++

c# - 如何通过 SWIG 将 C++ 复数引入 C# 应用程序?

multithreading - 多线程方法与 Akka Actor 模型

c# - 在不阻塞的情况下防止一个线程上出现多个 MessageBox

c++ - C++中映射中迭代器概念的混淆