寻找单写器/多读取器锁的最小futex-based实现,除了单个4字节的futex状态变量外,不需要任何空间开销。
一些背景知识:我有一个应用程序,它将在数千万到数亿个小对象中嵌入一个锁。由于锁的细粒度特性和应用程序的结构,我期望最小的争用。此外,作家将是稀有的,而有竞争力的作家更是罕见。由于所有这些原因,在这个特定的环境中,(在理论上)容易出现“雷鸣般的”现象的解决方案是相当可以接受的。
发布于 2016-07-24 23:33:08
您可以在https://gist.github.com/smokku/653c469d695d60be4fe8170630ba8205上找到我的实现
这个想法是,可以只有一个线程获取写锁(futex值0
),锁可以是打开的(futex值1
),或者可以有许多读取线程(futex值大于1
)。因此,低于1
(只有一个)的值会阻塞futex上的读取器和写入器,而高于1
的值只会阻塞写入器。解锁线程会唤醒其中一个等待线程,但您需要小心,不要消耗仅由写线程唤醒的读取器。
#define cpu_relax() __builtin_ia32_pause()
#define cmpxchg(P, O, N) __sync_val_compare_and_swap((P), (O), (N))
static unsigned _lock = 1; // read-write lock futex
const static unsigned _lock_open = 1;
const static unsigned _lock_wlocked = 0;
static void _unlock()
{
unsigned current, wanted;
do {
current = _lock;
if (current == _lock_open) return;
if (current == _lock_wlocked) {
wanted = _lock_open;
} else {
wanted = current - 1;
}
} while (cmpxchg(&_lock, current, wanted) != current);
syscall(SYS_futex, &_lock, FUTEX_WAKE_PRIVATE, 1, NULL, NULL, 0);
}
static void _rlock()
{
unsigned current;
while ((current = _lock) == _lock_wlocked || cmpxchg(&_lock, current, current + 1) != current) {
while (syscall(SYS_futex, &_lock, FUTEX_WAIT_PRIVATE, current, NULL, NULL, 0) != 0) {
cpu_relax();
if (_lock >= _lock_open) break;
}
// will be able to acquire rlock no matter what unlock woke us
}
}
static void _wlock()
{
unsigned current;
while ((current = cmpxchg(&_lock, _lock_open, _lock_wlocked)) != _lock_open) {
while (syscall(SYS_futex, &_lock, FUTEX_WAIT_PRIVATE, current, NULL, NULL, 0) != 0) {
cpu_relax();
if (_lock == _lock_open) break;
}
if (_lock != _lock_open) {
// in rlock - won't be able to acquire lock - wake someone else
syscall(SYS_futex, &_lock, FUTEX_WAKE_PRIVATE, 1, NULL, NULL, 0);
}
}
}
https://stackoverflow.com/questions/3964776
复制相似问题