【问题标题】:Is unique_ptr thread safe?unique_ptr 线程安全吗?
【发布时间】:2012-07-14 09:28:13
【问题描述】:

unique_ptr 线程安全吗?下面的代码不可能两次打印相同的数字吗?

#include <memory>
#include <string>
#include <thread>
#include <cstdio>

using namespace std;

int main()
{
    unique_ptr<int> work;

    thread t1([&] {
        while (true) {
            const unique_ptr<int> localWork = move(work);
            if (localWork)
                printf("thread1: %d\n", *localWork);
            this_thread::yield();
        }
    });

    thread t2([&] {
        while (true) {
            const unique_ptr<int> localWork = move(work);
            if (localWork)
                printf("thread2: %d\n", *localWork);
            this_thread::yield();
        }
    });

    for (int i = 0; ; i++) {
        work.reset(new int(i));

        while (work)
            this_thread::yield();
    }

    return 0;
}

【问题讨论】:

    标签: c++ multithreading c++11 thread-safety unique-ptr


    【解决方案1】:

    unique_ptr 在正确使用时是线程安全的。你打破了不成文的规则:你永远不能通过引用在线程之间传递 unique_ptr。

    unique_ptr 背后的理念是它始终只有一个(唯一的)所有者。因此,您始终可以在线程之间安全地传递它而无需同步——但您必须按值传递它,而不是按引用传递。一旦您为 unique_ptr 创建别名,您将失去唯一性属性并且所有赌注都已取消。不幸的是,C++ 不能保证唯一性,因此您必须遵守一个必须严格遵守的约定。不要为 unique_ptr 创建别名!

    【讨论】:

    • 有趣的观察。我试着思考什么时候通过引用传输 unique_ptr 是有意义的。我的意思是当您不想传递所有权时。
    • 如果“在线程之间传递”意味着使用 unique_ptr 参数启动一个新线程,那么您可以将 unique_ptr 替换为几乎任何类型并仍然称其为线程安全的。正确使用任何东西都是线程安全的:)
    • 你确定吗?我内心的偏执程序员告诉我,如果你在线程之间传递 up 它是 UB,因为你不确保 seq_cst,也就是如果 up 指向的内容被线程 1 修改,然后 up 被传递给线程 2,那么线程 2 可能会看到陈旧的值指着东西。
    • @ValentinMilea :将任意指针传递给线程是不安全的。您可能正在考虑传递具有复制语义的值——这些确实是安全的。
    • -1。当人们询问线程安全时,他们实际上是在问从多个线程同时访问对象的一个实例是否安全。从这个意义上说,unique_ptr 并不比T* 更安全。
    【解决方案2】:

    不,它不是线程安全的。

    两个线程都可能move 工作指针没有显式同步,因此两个线程有​​可能获得相同的值,或者两者都获得一些无效的指针......这是未定义的行为。

    如果你想正确地做这样的事情,你可能需要使用std::atomic_exchange这样的东西,这样两个线程都可以读取/修改具有正确语义的共享工作指针。

    【讨论】:

    • “令人兴奋的是,当这种情况发生时,它也会导致整数的双重释放。”它可能。它可能不会。它可能导致根本不释放整数。这可能会导致两个移动版本都具有指针值的一半。它可以做各种各样的事情。
    • 没错,我对架构做了一些没有真正保证的假设。
    【解决方案3】:

    Msdn

    以下线程安全规则适用于标准中的所有类 C++ 库(除了 shared_ptr 和 iostream 类,如所述 下面)。

    单个对象是线程安全的,可以从多个线程中读取。为了 例如,给定一个对象 A,从线程 1 中读取 A 是安全的,并且 同时来自线程 2。

    如果单个对象正在由一个线程写入,则所有读取 并且必须在相同或其他线程上写入该对象 受保护。例如,给定一个对象 A,如果线程 1 正在写入 A,那么必须阻止线程 2 读取或写入 A。

    读取和写入一个类型的一个实例是安全的,即使另一个实例 线程正在读取或写入相同类型的不同实例。 例如,给定相同类型的对象 A 和 B,如果 A 正在线程 1 中写入,B 正在线程 2 中读取。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-04
      • 2020-04-15
      • 2013-05-05
      • 2011-07-04
      • 2014-04-26
      • 2012-11-30
      • 2010-12-30
      • 2013-03-12
      相关资源
      最近更新 更多