【发布时间】:2017-02-20 03:25:56
【问题描述】:
我有一个大型数据数组(3e9 个元素),我正在多个线程中更新它的值。我刚刚发现有竞争条件。
我认为没有必要锁定整个功能,因为元素之间是相互独立的,data[1] 和data[234] 的更新可以安全地同时进行。
我还发现data[] 中每个元素的最高位永远不会被使用。在该位上实现 GCC 原子内置锁是否安全?
我的代码如下,但似乎出现了死锁。
const unsigned short LOCK_MASK = 1<<15;
unsigned short * lock = &(data[position]);
unsigned short oldLock, newLock;
//lock
do {
oldLock = *lock;
newLock = oldLock ^ LOCK_MASK;
} while ((oldLock & LOCK_MASK) || !__sync_bool_compare_and_swap(lock, oldLock, newLock));
//update data[position] here
...
...
...
//unlock
*lock ^= LOCK_MASK;
我也阅读了这篇文章 (Lightweight spinlocks built from GCC atomic operations?) 并在我的data 上添加了volatile
EDIT在我的设计中,0表示解锁,1表示锁定
【问题讨论】:
-
获取锁之前的所有读取都需要同步。特别是,
oldLock = *lock;是错误的,它需要是原子的。就目前而言,如果(oldLock & LOCK_MASK)曾经为真,优化器可能会假设*lock永远不会改变。 -
一种更保守的方法可能是分配适当数量的真正互斥锁(或自旋锁或您想使用的任何机制)并使用它们来同步对数据的访问。例如如果你有一个 M 互斥体数组,那么在读取或写入数据数组中的值 #i 之前,只需让每个线程锁定互斥体 #(i%M)。调整 M 的值,直到找到它的最小值,其中互斥体的争用仍然可以接受。
标签: c++ multithreading gcc compare-and-swap