锁定全局内存中二维数组中行的读/写

时间:2016-05-09 10:40:20

标签: arrays cuda locking gpu

我有二维数组,并且有一些线程可以更新数组中的行。可能是两个或多个线程需要一次更新一行。如果有线程更新它,我需要锁定试图访问同一行的线程。

1 个答案:

答案 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上调度多个块),来自不同块的线程很可能会尝试访问竞赛中的行。