想要一种在C++中交换两个指针的有效方法

Want an efficient way to swap two pointers in C++

本文关键字:两个 指针 方法 有效 交换 C++ 一种      更新时间:2023-10-16

我有两个指针,它们指向多线程C++应用程序中的一个大图形对象。我试着每5分钟换一次。哪种方式安全且性能最佳?C++11atomic<>是个不错的选择吗?

交换需要是原子交换吗?也就是说,你需要保证另一个线程在交换时不能观察到它们都具有相同的值吗?

如果您不需要保证交换是原子的,那么只需使用两个std::atomic<T*>对象并使用临时的交换它们

T* tmp = p1;
p1 = p2.load();
p2 = tmp;

如果你需要原子交换,那么在标准C++中进行交换,你需要将它们存储在相同的结构中,这样它就可以在一个步骤中更新,例如

struct TwoPointers { T* p1; T* p2; }
std::atomic<TwoPointers> p;

然后你可以这样交换它们:

auto old = p.load();
p = { old.p2, old.p1 };

这使用了双字原子操作,可以在幕后用互斥实现,因此通过临时的简单分配可能会执行得更好,但我怀疑每五分钟一次会有什么不同。

上面的两个版本都假设任何时候只有一个线程会尝试交换它们,因为尽管加载旧值是原子式完成的,写入新值是原子性完成的,但在这两个步骤之间有一个窗口,在这个窗口中,另一个线程可以更改指针值。如果这是一个问题,请使用这样的std::atomic<TwoPointers>

auto old = p.load();
while (!p.compare_exchange_strong(old, { old.p2, old.p1 }))
{ };

在循环中使用compare_exchange_strong比单个原子存储稍慢,但如果每五分钟只发生一次,则不会注意到差异。

这种TwoPointers解决方案也意味着两个指针共享一条缓存线,但如果它们是只读的,每五分钟交换一次,那么这就不是问题。