【问题标题】:Thread safe unique_ptr move线程安全的 unique_ptr move
【发布时间】:2012-12-13 19:11:31
【问题描述】:

是否可以使用 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 声明为我编译,但我不知道如何初始化它并采取行动。

【问题讨论】:

    标签: c++ c++11 thread-safety move-semantics unique-ptr


    【解决方案1】:

    不,这是不可能的。

    您传递给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 当前不拥有令牌时其他线程会得到什么?

    【讨论】:

    • 感谢 std::shared_ptr 的回答和讨论。意图:代码被简化,但我认为即使这样它也会将 nullptr 返回到以后的线程,允许调用者发现令牌不可用。问题在这里解决了,我会在其他评论中解释。
    • 客户端对DataManager进行两种操作:读、写。只有一个客户可以在时间写入。 客户端不是线程 - 有时是的,有时可能会为客户端启动后台作业。读/写不是简单的操作,而是遵循DataManager和客户端之间复杂的通信协议。客户端请求不一定要在令牌可用之前被阻止,但有时会主动拒绝。为了在混乱中定位,我提出了这个 SyncToken - 作者需要借用 SyncToken 并在完成后调用 returnSyncToken(unique_ptr)。
    猜你喜欢
    • 1970-01-01
    • 2021-06-04
    • 2013-05-05
    • 1970-01-01
    • 2017-02-01
    • 2014-02-27
    • 1970-01-01
    • 2021-12-19
    • 1970-01-01
    相关资源
    最近更新 更多