线程安全unique_ptr移动

Thread safe unique_ptr move

本文关键字:ptr 移动 unique 安全 线程      更新时间:2023-10-16

是否可以使用 c++11 原子操作安全地移动unique_ptr?

目前我有这样的代码

std::unique_ptr<SyncToken> DataManager::borrowSyncToken()
{
    std::unique_lock<std::mutex> syncTokenLock(syncTokenMutex);
    return std::move(syncToken);
}

我想知道是否有一些更优雅的方式,比如简单地声明:

std::atomic<std::unique_ptr<SyncToken>> syncToken;

并避免了互斥锁的需要。或者可能我根本不需要关心这里的锁,std::move 已经是原子的了?

经过我到目前为止的研究,在我看来:

  • std::move 本身不是原子的,需要有一些同步,否则同时调用我的方法的 2 个线程最终可能会得到一些未定义指针的 2 个副本。
  • std::atomic 声明为我编译,但我不知道如何初始化它并进行移动。

不,这是不可能的。

传递给std::atomic的值T需要简单可复制,而std::unique_ptr不是。 std::atomic::loadstd::atomic::store等操作按值获取 T 对象。

std::atomic中打包某些东西也不会从值原子进行操作。

在原子上下文中使用std::unique_ptr时,您必须考虑在管理资源时可能会遇到问题的事实。你永远不知道有多少线程仍然引用你的数据,这个问题可以通过使用原子引用计数的std::shared_ptr来解决。(您需要使用 std::atomic_is_lock_free 函数检查它是否真的是原子的。

在查看您的代码时,我也偶然发现的一件事是borrowSyncToken函数的意图。这称为借用,但您可以通过移出std::unique_ptr将令牌的所有权传递给调用方,所有权如何传回,当 DataManager 当前不拥有令牌时,其他线程会得到什么?