我有二维数组,并且有一些线程可以更新数组中的行。可能是两个或多个线程需要一次更新一行。如果有线程更新它,我需要锁定试图访问同一行的线程。
答案 0 :(得分:1)
如果您的线程只需更新行中的一个元素,那么应该执行简单的原子操作(例如atomicAdd()
)。
如果必须对行的多个元素执行相关操作,则需要实现某种“临界区”控件。例如:
#define ROW_COUNT 10
__global__
void the_kernel( ... ) {
// block-level shared array indicating the locking state of each row
__shared__ int locks[ ROW_COUNT ];
// initialize shared array
if ( threadIdx.x == 0 ) memset( locks, 0, sizeof( int ) * ROW_COUNT );
__syncthreads();
// suppose the current thread need to update row #3
int row_idx = 3;
// thread-local variable indicating whether current thread has access to the target row
bool updating = false;
do {
// return value from atomicCAS will be 0 when no other thread is updating row #3
// otherwise current thread should loop until the row lock is released by other threads
updating = (atomicCAS( locks + row_idx, 0, -1 ) == 0);
if (updating) {
// entered critical section, do the work!
// before we release the lock, we should make the changes made by current thread visible to other threads
// we can not use __syncthreads() as this is inside a conditional branch, so we have to use __threadfence()
__threadfence();
// now releasing the lock
atomicExch( locks + row_idx, 0 );
}
} while ( !updating );
}
话虽这么说,这个设计本质上是串行的,除了一个更新行的线程之外的所有线程都将循环并等待轮到他们。会有性能损失,所以只有在绝对必要时才使用它。
请注意,只有当所有线程都可以放入一个块(例如总共1024个线程)时,该结构才有效,因为共享内存阵列锁定不能跨块工作。在具有多个SM的GPU上(即可以在不同的SM上调度多个块),来自不同块的线程很可能会尝试访问竞赛中的行。