web-dev-qa-db-fra.com

__Syncthreads () synchronise-t-il tous les threads de la grille?

... ou simplement les fils de la chaîne ou du bloc actuel?

De plus, lorsque les threads d'un bloc particulier rencontrent (dans le noyau) la ligne suivante

__shared__  float srdMem[128];

vont-ils simplement déclarer cet espace une fois (par bloc)?

Ils fonctionnent tous de manière asynchrone, donc si le thread 23 du bloc 22 est le premier thread à atteindre cette ligne, puis le thread 69 du bloc 22 est le dernier à atteindre cette ligne, le thread 69 saura qu'il a déjà été déclaré?

La commande __syncthreads() est une barrière de synchronisation au niveau du bloc . Cela signifie qu'il peut être utilisé en toute sécurité lorsque tous les fils d'un bloc atteignent la barrière. Il est également possible d'utiliser __syncthreads() dans du code conditionnel, mais uniquement lorsque tous les threads évaluent de manière identique un tel code, sinon l'exécution est susceptible de bloquer ou de produire des effets secondaires inattendus [4] .

Exemple d'utilisation de __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;        
}

Pour synchroniser tous les threads d'une grille, il existe actuellement et non un appel d'API natif. Une façon de synchroniser les threads au niveau de la grille consiste à utiliser des appels de noyau consécutifs car à ce stade, tous les threads se terminent et recommencent à partir du même point. Il est également communément appelé synchronisation CPU ou synchronisation implicite. Ils sont donc tous synchronisés.

Exemple d'utilisation de cette technique ( source ):

CPU synchronization

Concernant la seconde question. Oui , il déclare la quantité de mémoire partagée spécifiée par bloc. Tenez compte du fait que la quantité de mémoire partagée disponible est mesurée par [~ # ~] sm [~ # ~]. Donc, il faut être très prudent comment la mémoire partagée est utilisée avec la configuration de lancement .

52
KiaMorot

__syncthreads() attend que tous les threads d'un même bloc aient atteint la commande et tous les threads d'un warp - cela signifie que tous les warps appartenant à un blockblock doivent atteindre l'instruction.

Si vous déclarez de la mémoire partagée dans un noyau, le tableau ne sera visible que pour un seul threadblock. Ainsi, chaque bloc aura son propre bloc de mémoire partagée.

12
hubs

Je suis d'accord avec toutes les réponses ici, mais je pense que nous manquons un point important ici avec la première question. Je ne réponds pas à la deuxième réponse car elle a été parfaitement répondue dans les réponses ci-dessus.

L'exécution sur GPU se produit en unités de distorsion. Une chaîne est un groupe de 32 threads et à un moment donné, chaque thread d'une chaîne particulière exécute la même instruction. Si vous allouez 128 threads dans un bloc, ses (128/32 =) 4 déformations pour un GPU.

Maintenant, la question devient "Si tous les threads exécutent la même instruction, pourquoi la synchronisation est-elle nécessaire?". La réponse est que nous devons synchroniser les chaînes qui appartiennent au [~ # ~] même [~ # ~] bloc . __syncthreads ne synchronise pas les threads dans une chaîne, ils sont déjà synchronisés. Il synchronise les chaînes qui appartiennent au même bloc.

C'est pourquoi la réponse à votre question est: __syncthreads ne synchronise pas tous les threads dans une grille, mais les threads appartenant à un bloc pendant que chaque bloc s'exécute indépendamment.

Si vous souhaitez synchroniser une grille, divisez votre noyau (K) en deux noyaux (K1 et K2) et appelez les deux. Ils seront synchronisés (K2 sera exécuté après la fin de K1).

9
Adarsh