__syncthreads()
如果不是所有块线程都进入它,则会导致未定义的行为或死锁。
通过单个线程块扫描大于块大小的空间,
copyLimit = 8192; // assuming 8k is going to be copied
w = blockDim.x; // this will be running inside copyLimit, nLoop times to fill all of it, but masked by some if-else to not overflow it
nLoop = copyLimit/w + 1;
for(int i=0;i<nLoop;i++)
{
// load from global to shared
if(threadIdx.x+i*w<copyLimit)
doLoad();
}
__syncthreads(); // only once! A loading doesn't need sync with a loading.
for(int i=0;i<nLoop;i++)
{
if(threadIdx.x+i*w<copyLimit)
{
// compute, assuming its just embarrassingly parallel
}
}
// can also compute here too depending on compute job, to use all pipelines
for(int i=0;i<nLoop;i++)
{
// save to global from shared
if(threadIdx.x+i*w<copyLimit)
doStore();
}
__syncthreads(); // only once!
// so that you can use stored values by other threads
doSomeWork(sharedArray);
如果每个线程的循环周期数未知(例如处理不平衡的树),则有一个共享的活动计数器。
active=1; // start working
while(active>0)
{
// work
if(!isFinished())
doWork(); // sets isFinished() if it has no other job
// any syncthreads or syncwarp whatever you need to sync
__syncthreads(); // is not undefined behavior
// when thread finishes its job, its not active
if(isFinished())
activeList[threadIdx.x] = 0;
// reduction in a shared array, to find total number of active threads
// and broadcast it to all threads
active=reduceActiveThreads(); // includes its own syncthreads
}
// all block threads exit here together, as soon as last thread completes its job
如果有 Volta+ 架构,您也可以尝试它的 warp 版本,以减少循环中空闲线程的丢失周期。(依靠它的独立线程调度)。即使没有 Volta,warp 减少也可以比共享数组减少更快。
如果所有线程的周期数相同但在编译时未知,那么找到所有线程的最大值就足够了。然后使用它为块的所有线程循环该次数不会产生未定义的行为。
int nLoop = findNumCycles(threadIdx.x, someParameters);
nLoop = reduceN(nLoop, threadIdx.x); // max(of all nLoop values)
for(int i=0;i<nLoop;i++)
{
// can synchronize block now
__syncthreads();
}
// or here, only once, if there was only a loading from global into shared
__syncthreads();