70 votes

Pourquoi il y a un Fil.Sommeil(1).NET interne de la table de hachage?

Récemment j'ai lu la mise en œuvre de l' .NET Hashtable et ont rencontré un morceau de code qui n'est pas understable par moi. Partie du code est:

int num3 = 0;
int num4;
do
{
   num4 = this.version;
   bucket = bucketArray[index];
   if (++num3 % 8 == 0)
     Thread.Sleep(1);
}
while (this.isWriterInProgress || num4 != this.version);

Tout le code est dans public virtual object this[object key] de System.Collections.Hashtable (mscorlib Version=4.0.0.0).

Et la question est:

Quelle est la raison d'avoir Thread.Sleep(1) ?

70voto

Hans Passant Points 475940

Sleep(1) est documenté de manière à Windows de rendement du processeur et de permettre à d'autres threads de s'exécuter. Vous pouvez trouver ce code dans la Source de Référence avec les commentaires:

   // Our memory model guarantee if we pick up the change in bucket from another processor,
   // we will see the 'isWriterProgress' flag to be true or 'version' is changed in the reader.
   //
   int spinCount = 0;
   do {
       // this is violate read, following memory accesses can not be moved ahead of it.
       currentversion = version;
       b = lbuckets[bucketNumber];

       // The contention between reader and writer shouldn't happen frequently.
       // But just in case this will burn CPU, yield the control of CPU if we spinned a few times.
       // 8 is just a random number I pick.
       if( (++spinCount) % 8 == 0 ) {
           Thread.Sleep(1);   // 1 means we are yeilding control to all threads, including low-priority ones.
       }
   } while ( isWriterInProgress || (currentversion != version) );

Le isWriterInProgress variable est un volatile bool. L'auteur a eu quelques difficultés avec l'anglais "violer lire" est "volatile lire". L'idée de base est d'essayer de ne pas céder, au fil des changements de contexte sont très cher, avec un peu d'espoir que l'auteur se fait rapidement. Si cela ne fonctionne pas dehors alors explicitement de rendement pour éviter de brûler de l'uc. Cela aurait probablement été écrit avec Spinlock aujourd'hui, mais à la table de hachage est très ancienne. Que sont les hypothèses sur le modèle de mémoire.

7voto

Slokun Points 2861

Sans avoir accès au reste de la mise en œuvre du code, je ne peux que faire une hypothèse sur la base de ce que vous avez posté.

Cela dit, on dirait qu'il essaie de mettre à jour quelque chose dans la table de hachage, soit en mémoire ou sur disque, et de faire une boucle infinie lors de l'attente pour elle à la fin (comme on le voit par la vérification de l' isWriterInProgress).

Si c'est un processeur single-core, il ne peut exécuter un thread à la fois. Va dans une boucle continue comme cela peut facilement signifier l'autre thread n'a pas une chance de s'exécuter, mais l' Thread.Sleep(1) donne le processeur d'une chance de donner du temps à l'écrivain. Sans attendre, le thread d'écriture ne peut jamais obtenir une chance de courir, et de ne jamais se terminer.

5voto

David Seiler Points 6212

Je n'ai pas lu la source, mais il ressemble à un lockless simultanéité chose. Vous êtes en train de lire à partir de la table de hachage, mais quelqu'un d'autre pourrait l'être par écrit, afin de vous permettre d'attendre jusqu' isWriterInProgress n'est pas définie et la version que vous avez lu n'a pas changé.

Cela n'explique pas pourquoi par exemple nous toujours attendre au moins une fois. EDIT: c'est parce que nous n'avons pas, merci @Maciej pour le pointage. Quand il n'y a pas de conflit nous procédons immédiatement. Je ne sais pas pourquoi 8 est le nombre magique au lieu de par exemple 4 ou 16.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X