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

How to perform double buffering with atomic pointers?

这里是 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 对其执行一些工作。我的问题:我是否可以安全地假设共享对象将 "protected" 对抗数据竞争,而 thread_a 对其调用 doSomething(),如 (1) 中所做的那样?

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

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

也许在这里互斥锁是更好的选择?

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

您的设计存在问题,正如某些程序员老兄在他的回答中所建议的那样。但是,如果您使用 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