38

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

3 回答 3

42

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

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

于 2012-07-14T17:30:40.923 回答
29

不,它不是线程安全的。

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

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

于 2012-07-14T09:37:20.127 回答
10

根据Msdn

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

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

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

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

于 2012-07-14T09:34:37.947 回答