如何使用原子指针执行双重缓冲?

时间:2018-10-30 09:24:54

标签: c++ multithreading atomic

这里有原子新手。我的代码当前看起来像这样(简化):

std::atomic<Object*> object;

void thread_a()
{
  object.load()->doSomething(); // (1)
}

void thread_b()
{
    Object* oldObject = object.load();
    Object* newObject = new Object();
    // Update new object accordingly...

    while (!object.compare_exchange_weak(oldObject, newObject));

    delete oldObject;
}

换句话说,我的想法是让thread_b原子交换共享对象(双缓冲),而thread_a对其执行一些工作。我的问题:我可以安全地假设在thread_a对其上调用doSomething()时,共享对象将被“保护”以防止数据争用吗,如(1)所述吗?

2 个答案:

答案 0 :(得分:8)

使用load()获取指针是原子的,但是对doSomething()本身的调用不是原子的。

这意味着可以在调用load()之后但在调用doSomething()之前交换指针(这意味着在错误且现在已删除的对象上调用doSomething())。

也许互斥锁可能是一个更好的选择?

答案 1 :(得分:3)

我经常这样做,但是...使用共享指针,并且它是无锁的!

正如某些程序员Dude在回答中所建议的那样,您的设计存在问题。但是,如果您使用shared_ptr进行此操作,并且您的程序逻辑允许这样做,那么您会没事的。

shared_ptr一起使用的原因是,只要您的对象位于其他地方,就不会强行删除它。因此,这是您的操作方式:

std::shared_ptr<Object> object;

void thread_a()
{
  std::atomic_load(&object)->doSomething(); // (1)
}

void thread_b()
{
    std::shared_ptr<Object> oldObject = std::atomic_load(&object);
    std::shared_ptr<Object> newObject = std::make_shared<Object>();
    // Update new object accordingly...

    while (!std::atomic_compare_exchange_weak(object, oldObject, newObject));
}

编辑:此atomic_load专用于shared_ptr。这似乎引起了评论的混乱:https://en.cppreference.com/w/cpp/memory/shared_ptr/atomic