Extraño comportamiento de Console.ReadKey () con multihilo

Tengo un problema extraño cuando uso Console.ReadKey() en un progtwig multiproceso.

Mi pregunta es: ¿por qué está pasando esto? ¿Es un error, o es porque estoy abusando de la Console ? (Tenga en cuenta que se supone que la consola debe ser segura para los hilos, de acuerdo con la documentación ).

Es más fácil explicar esto con código:

 using System; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication2 { internal class Program { private static void Main(string[] args) { Console.WriteLine("X"); // Also try with this line commented out. Task.Factory.StartNew(test); Console.ReadKey(); } private static void test() { Console.WriteLine("Entering the test() function."); Thread.Sleep(1000); Console.WriteLine("Exiting the test() function."); } } } 

¿Qué crees que se imprimirá si lo ejecutas y no presionas una tecla?

La respuesta es justamente lo que esperarías:

 X Entering the test() function. Exiting the test() function. 

Ahora comente la Console.WriteLine("X") y ejecútela nuevamente (sin presionar una tecla). Esperaba ver esta salida:

 Entering the test() function. Exiting the test() function. 

En cambio, no veo nada . Luego, cuando presiono una tecla, dice:

 Entering the test() function. 

…y eso es. El progtwig sale (por supuesto) y no tiene tiempo para llegar a la siguiente WriteLine() .

Encuentro este comportamiento muy misterioso. Es fácil evitarlo, pero estoy intrigado de por qué sucede.

[EDITAR]

Si agrego un Thread.Sleep(1) inmediatamente antes de Console.ReadKey() funciona como se esperaba. Por supuesto, esto no debería ser necesario ya que Console.ReadKey() debería esperar para siempre de todos modos.

¿Así que parece que podría ser algún tipo de condición de carrera?

Más información: Servy ha encontrado (y he duplicado) que la línea Console.WriteLine("Entering the test() function.") está bloqueando hasta que se presione cualquier tecla.

Configuración de comstackción

Visual Studio 2012, Windows 7 x64, Quad Core, inglés (Reino Unido).

Probé todas las combinaciones de .Net4, .Net4.5, x86, AnyCPU y depuración y liberación, y ninguna de ellas funciona en mi PC. Pero sucedió algo realmente extraño. Comenzó a funcionar cuando probé por primera vez la versión AnyCPU para .Net4, pero luego dejó de funcionar de nuevo. Se parece mucho a una condición de carrera que solo afecta a algunos sistemas.

Esta es una condición de carrera. Esto es lo que sucede cuando la primera Console.WriteLine no está allí:

  1. La tarea se crea, pero no se ejecuta
  2. Console.ReadKey se ejecuta, toma un locking en Console.InternalSyncObject y bloquea la espera de entrada
  3. La consola Console.WriteLine llama a Console.Out, que llama a Console.InitializeStdOutError para la primera inicialización para configurar las transmisiones de la consola
  4. Console.InitializeStdOutError intenta bloquear Console.InternalSyncObject, pero Console.ReadKey ya lo tiene, por lo que bloquea
  5. El usuario presiona una tecla y Console.ReadKey regresa, liberando el locking
  6. La llamada a Console.WriteLine se desbloquea y finaliza la ejecución
  7. El proceso sale, porque no hay nada en Main después de la llamada ReadKey
  8. El código restante en la Tarea no tiene oportunidad de ejecutarse

La razón por la que se comporta de manera diferente cuando se deja Console.WriteLine allí es porque la llamada a Console.InitializeStdOutError no ocurre en paralelo con Console.ReadKey.

Entonces la respuesta corta es: sí, estás abusando de Console. Puede inicializar la consola usted mismo (desmarcando Console.Out), o esperar en un evento después de iniciar la Tarea, pero antes de ReadKey, y luego hacer que la Tarea señalice el evento después de llamar a Console.WriteLine la primera vez.

Se confirma una falla interna en .NET 4.5. Se ha informado, por ejemplo, aquí: https://connect.microsoft.com/VisualStudio/feedback/details/778650/undocumented-locking-behaviour-in-system-console

Esto funcionó en .NET 3.5 y .NET 4.

Más información: http://blogs.microsoft.co.il/blogs/dorony/archive/2012/09/12/console-readkey-net-4-5-changes-may-deadlock-your-system.aspx

Puede usar una solución simple para iniciar las estructuras internas y evitar el locking. Solo agregue esto al principio (de @renestein):

 Console.Error.WriteLine(); Console.WriteLine(); 

Esto probablemente se está produciendo PORQUE es multihilo. El hilo principal se está moviendo y saliendo antes de que su tarea asincrónica tenga la oportunidad de informar. Cuando sale el hilo principal, todos los hilos secundarios son eliminados.

¿Qué pasa si coloca una espera antes de la ReadKey? ¿lo muestra correctamente?