thread sirve que para c# .net hashtable thread-sleep spinwait

sirve - timer sleep c#



¿Por qué hay un Thread.Sleep(1) en.NET Hashtable interno? (3)

No he leído la fuente, pero parece una cosa de concurrencia sin cerradura. Está intentando leer de la tabla hash, pero es posible que alguien más esté escribiendo, por lo que espera hasta que isWriterInProgress esté configurado y la versión que ha leído no haya cambiado.

Esto no explica por qué, por ejemplo, siempre esperamos al menos una vez. EDITAR: eso es porque no, gracias @Maciej por señalar eso. Cuando no hay disputa, procedemos de inmediato. Sin embargo, no sé por qué 8 es el número mágico en lugar de, por ejemplo, 4 o 16.

Recientemente estuve leyendo la implementación de .NET Hashtable y encontré una pieza de código que no entiendo. Parte del código es:

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);

Todo el código está dentro public virtual object this[object key] de System.Collections.Hashtable (mscorlib Version = 4.0.0.0).

La pregunta es:

¿Cuál es el motivo de tener Thread.Sleep(1) allí?


Sin tener acceso al resto del código de implementación, solo puedo hacer una conjetura basada en lo que has publicado.

Dicho esto, parece que intenta actualizar algo en el Hashtable, ya sea en la memoria o en el disco, y haciendo un ciclo infinito mientras espera que termine (como se ve al verificar el isWriterInProgress ).

Si se trata de un procesador de núcleo único, solo puede ejecutar un hilo por vez. Ir en un bucle continuo como este podría significar fácilmente que el otro subproceso no tiene la posibilidad de ejecutarse, pero el Thread.Sleep(1) le da al procesador la oportunidad de darle tiempo al escritor. Sin la espera, el hilo del escritor nunca tendrá la oportunidad de ejecutarse, y nunca se completará.


Sleep (1) es una forma documentada en Windows para ceder el procesador y permitir que se ejecuten otros subprocesos. Puede encontrar este código en la fuente de referencia con comentarios:

// 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) );

La variable isWriterInProgress es un bool volátil. El autor tuvo algunos problemas con el inglés "violate read" es "lectura volátil". La idea básica es tratar de evitar ceder, los cambios de contexto de hilo son muy caros, con la esperanza de que el escritor se haga rápidamente. Si eso no funciona, explícitamente cede para evitar la quema de la CPU. Probablemente esto se haya escrito hoy con Spinlock, pero Hashtable es muy antiguo. Como son las suposiciones sobre el modelo de memoria.