2012-05-25 14 views
19

Cuando ejecuto el código siguiente en el modo de depuración , que va a terminar y salir con éxito. Sin embargo, si se me acaba el siguiente código en modo de liberación , que va a quedar atrapado en un bucle infinito y nunca termina.bucle infinito en modo de lanzamiento

static void Main(string[] args) 
{ 
    bool stop = false; 

    new Thread(() => 
    { 
     Thread.Sleep(1000); 
     stop = true; 
     Console.WriteLine("Set \"stop\" to true."); 

    }).Start(); 

    Console.WriteLine("Entering loop."); 

    while (!stop) 
    { 
    } 

    Console.WriteLine("Done."); 
} 

Qué optimización está causando el mismo quede atascado en un bucle infinito?

+0

¿no hay necesidad de sincronizar el acceso a 'stop' entre los hilos? –

+0

Eso es causado por algunas cosas de optimación. La compilación construirá un verdadero instat de parada. – rekire

+0

Eche un vistazo a las nuevas clases CancellationToken. Fueron inventados para resolver este problema. http://msdn.microsoft.com/en-us/library/dd997364.aspx –

Respuesta

18

Supongo que el caché del procesador de la variable stop en el hilo principal. En el modo de depuración, el modelo de memoria es más estricto porque el depurador debe ser capaz de proporcionar una vista sensata del estado de la variable en todos los subprocesos.

intentar hacer un campo y marcándolo como volatile:

volatile bool stop = false; 

static void Main(string[] args) 
{ 

    new Thread(() => 
    { 
     Thread.Sleep(1000); 
     stop = true; 
     Console.WriteLine("Set \"stop\" to true."); 

    }).Start(); 

    Console.WriteLine("Entering loop."); 

    while (!stop) 
    { 
    } 

    Console.WriteLine("Done."); 
} 
+0

Volatile es bueno para ser correcto, pero para evitar la optimización, parece que convertirlo en campo en lugar de variable local es suficiente. –

+0

@AlexeiLevenkov Podría estar equivocado, pero creo que es un detalle de implementación de la CLR, y teóricamente (aunque probablemente no en la práctica) sujeto a cambios. –

+0

Me pregunto por qué no está sincronizando el acceso a la variable. Siempre hago esto, ya que supongo que no es una operación atómica obtener/establecer una variable 'bool'. ¿Estoy equivocado en esto? –

11

Porque no es hilo de seguridad de actualizar la variable hilo principal stop en el interior del hilo hijo. Siempre será impredecible. Para trabajar con cualquier situación como esta, eche un vistazo al this article.

La palabra clave volátil indica al compilador para generar una adquieren-valla en cada acceso de lectura a partir de ese campo, y una liberación-valla en cada escritura a ese campo. Una valla impide adquirir-otra lecturas/escrituras se mueva antes de la valla; una valla de liberación impide que otras lecturas/escrituras se muevan después de la valla. Estos “medias” cercas son más rápidas que las cercas completo porque le dan al tiempo de ejecución y el alcance de hardware más para la optimización.

0

Tema código inseguro es impredecible. El problema principal es cambiar una variable de subproceso de otro subproceso. Haz que la variable sea global o volátil. Puede hacerlo siguiendo

static volatile bool stop = false; 

static void Main(string[] args) 
{  
    new Thread(() => 
    { 
     Thread.Sleep(1000); 
     stop = true; 
     Console.WriteLine("Set \"stop\" to true."); 

    }).Start(); 

    Console.WriteLine("Entering loop."); 

    while (!stop) 
    { 
    } 

    Console.WriteLine("Done."); 
} 
0

Parece que algún tipo de optimización para el valor de la variable local - cambiar a un campo que sea terminar bien (tenga en cuenta que el bloqueo volátil o correcta se debe utilizar en código real):

using System; 
using System.Threading; 

class Program 
{ 
    static bool stop = false; 
    static void Main(string[] args) 
    { 

     new Thread(() => 
     { 
      Thread.Sleep(1000); 
      stop = true; 
      Console.WriteLine("Set \"stop\" to true."); 

     }).Start(); 

     Console.WriteLine("Entering loop."); 

     while (!stop) 
     { 
     } 

     Console.WriteLine("Done."); 
    } 
}