在 MSVC STL 和 LLVMstd::atomic
中,非原子大小的 libc++ 实现都是使用自旋锁实现的。
libc++ ( Github ):
_LIBCPP_INLINE_VISIBILITY void __lock() const volatile {
while(1 == __cxx_atomic_exchange(&__a_lock, _LIBCPP_ATOMIC_FLAG_TYPE(true), memory_order_acquire))
/*spin*/;
}
_LIBCPP_INLINE_VISIBILITY void __lock() const {
while(1 == __cxx_atomic_exchange(&__a_lock, _LIBCPP_ATOMIC_FLAG_TYPE(true), memory_order_acquire))
/*spin*/;
}
inline void _Atomic_lock_acquire(long& _Spinlock) noexcept {
#if defined(_M_IX86) || (defined(_M_X64) && !defined(_M_ARM64EC))
// Algorithm from Intel(R) 64 and IA-32 Architectures Optimization Reference Manual, May 2020
// Example 2-4. Contended Locks with Increasing Back-off Example - Improved Version, page 2-22
// The code in mentioned manual is covered by the 0BSD license.
int _Current_backoff = 1;
const int _Max_backoff = 64;
while (_InterlockedExchange(&_Spinlock, 1) != 0) {
while (__iso_volatile_load32(&reinterpret_cast<int&>(_Spinlock)) != 0) {
for (int _Count_down = _Current_backoff; _Count_down != 0; --_Count_down) {
_mm_pause();
}
_Current_backoff = _Current_backoff < _Max_backoff ? _Current_backoff << 1 : _Max_backoff;
}
}
#elif
/* ... */
#endif
}
在考虑更好的实现时,我想知道用SeqLock替换它是否可行?如果读取不与写入竞争,优势将是廉价的读取。
我质疑的另一件事是是否可以改进 SeqLock 以使用 OS 等待。在我看来,如果读者观察到奇数,它可以使用原子等待底层机制(Linux futex
/Windows WaitOnAddress
)等待,从而避免自旋锁的饥饿问题。
在我看来,这似乎是可能的。尽管 C++ 内存模型目前不包括 Seqlock,但类型输入std::atomic
必须是可简单复制的,因此memcpy
如果使用足够的障碍来获得 volatile 等效项而不会严重破坏优化,则 seqlock 中的读/写将起作用并且将处理竞争。这将是特定 C++ 实现的头文件的一部分,因此它不必是可移植的。
关于在 C++ 中实现 SeqLock 的现有 SO Q&As(可能使用其他 std::atomic 操作)