web-dev-qa-db-ja.com

__syncthreads()はグリッド内のすべてのスレッドを同期しますか?

...または現在のワープまたはブロックのスレッドだけですか?

また、特定のブロック内のスレッドが(カーネル内で)遭遇すると、次の行

__shared__  float srdMem[128];

彼らはこのブロックをブロックごとに一度宣言するだけでしょうか?

これらはすべて非同期に動作するため、ブロック22のスレッド23がこの行に到達する最初のスレッドであり、ブロック22のスレッド69がこの行に到達する最後のスレッドである場合、スレッド69は既に宣言されていることを認識しますか?

__syncthreads()コマンドはblock level同期バリアです。つまり、ブロック内のすべてのスレッドがバリアに到達したときに使用しても安全です。条件付きコードで__syncthreads()を使用することもできますが、すべてのスレッドがこのようなコードを同じように評価する場合にのみ、そうしないと実行がハングするか、意図しない副作用 [4] を生成します。

__syncthreads()の使用例:( source

__global__ void globFunction(int *arr, int N) 
{
    __shared__ int local_array[THREADS_PER_BLOCK];  //local block memory cache           
    int idx = blockIdx.x* blockDim.x+ threadIdx.x;

    //...calculate results
    local_array[threadIdx.x] = results;

    //synchronize the local threads writing to the local memory cache
    __syncthreads();

    // read the results of another thread in the current thread
    int val = local_array[(threadIdx.x + 1) % THREADS_PER_BLOCK];

    //write back the value to global memory
    arr[idx] = val;        
}

現在、グリッド内のすべてのスレッドを同期するには、notネイティブAPI呼び出しがあります。グリッドレベルでスレッドを同期する1つの方法は、連続したカーネルコールを使用することです。その時点で、すべてのスレッドが終了し、同じポイントから再び開始します。一般に、CPU同期または暗黙的同期とも呼ばれます。したがって、それらはすべて同期されます。

この手法の使用例( source ):

CPU synchronization

secondの質問について。 はい、ブロックごとに指定された共有メモリの量を宣言します。使用可能な共有メモリの量は[〜#〜] sm [〜#〜]で測定されることを考慮してください。だから、非常に注意である必要があります共有メモリ起動設定

52
KiaMorot

__syncthreads()は、同じブロック内のすべてのスレッドがコマンドに到達し、ワープ内のすべてのスレッドに到達するまで待機します。つまり、スレッドブロックに属するすべてのワープがステートメントに到達する必要があります。

カーネルで共有メモリを宣言した場合、配列は1つのスレッドブロックのみに表示されます。したがって、各ブロックには独自の共有メモリブロックがあります。

12
hubs

私はここのすべての答えに同意しますが、私たちはここで重要なポイントを1つ欠落していると思います。上記の回答で完全に回答されたため、2番目の回答には答えていません。

GPUでの実行は、ワープの単位で行われます。ワープは32個のスレッドのグループであり、特定のワープの各スレッドは一度に同じ命令を実行します。ブロックに128個のスレッドを割り当てると、その(128/32 =)4個のGPUのワープが発生します。

問題は、「すべてのスレッドが同じ命令を実行している場合、なぜ同期が必要なのか?」になります。答えは、[〜#〜] same [〜#〜]ブロックに属するワープを同期する必要があるということです。 。 __syncthreadsはワープ内のスレッドを同期しません。すでに同期されています。同じブロックに属するワープを同期します。

だからこそ、あなたの質問への答えは次のとおりです。__syncthreadsはグリッド内のすべてのスレッドを同期するのではなく、各ブロックが独立して実行されるときに1つのブロックに属するスレッドを同期します。

グリッドを同期する場合は、カーネル(K)を2つのカーネル(K1とK2)に分割し、両方を呼び出します。それらは同期されます(K2はK1の終了後に実行されます)。

9
Adarsh