2009-07-18 11 views
20

El método System.Threading.ConcurrentQueue.TryDequeue arrojó una excepción el otro día que me tomó totalmente por sorpresa. Aquí está el seguimiento de la pila:Error en el constructor System.Random?

System.OverflowException: Negating the minimum value of a twos complement number is invalid. 
    at System.Math.AbsHelper(Int32 value) 
    at System.Random..ctor(Int32 Seed) 
    at System.Threading.Collections.ConcurrentQueue`1.TryDequeueCore(T& result) 
    at System.Threading.Collections.ConcurrentQueue`1.TryDequeue(T& result) 
    at MyProgram.ThreadProc() in c:\MyProgram\Main.cs:line 118 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
    at System.Threading.ThreadHelper.ThreadStart() 

Al principio pensé que el problema era que TryDequeueCore llama al constructor Random un valor equivocado. Pero una investigación más profunda revela que TryDequeueCore llama al constructor predeterminado. A mi me parece igual que el error está en el Random constructor:

.method public hidebysig specialname rtspecialname 
     instance void .ctor() cil managed 
{ 
    // Code size  12 (0xc) 
    .maxstack 8 
    IL_0000: ldarg.0 
    IL_0001: call  int32 System.Environment::get_TickCount() 
    IL_0006: call  instance void System.Random::.ctor(int32) 
    IL_000b: ret 
} // end of method Random::.ctor 

A medida que la documentación de la propiedad System.Environment.TickCount dice:

El valor de esta propiedad se deriva del temporizador del sistema y se almacena como un entero de 32 bits con signo. En consecuencia, si el sistema funciona de forma continua, TickCount aumentará de cero a Int32 .. ::. MaxValue durante aproximadamente 24,9 días, y luego saltar a Int32 .. ::. MinValue, que es un número negativo , después de la subasta volver a cero durante los próximos 24,9 días.

lo tanto, si se llama al constructor Random durante ese periodo de un milisegundo (después de que el sistema ha estado funcionando durante int.MaxValue milisegundos), que va a lanzar esta excepción.

¿Alguien tiene una solución? Para mi propio código, puedo hacer un método CreateRandom que obtiene el valor TickCount y lo comprueba en int.MinValue. ¿Pero qué hacer con el código que no tengo control?

Espero que el equipo de RTL corrija esto en .NET 4.0.

Actualización 22/07/2009: el equipo de BCL respondió al error y dijo que se había resuelto para el próximo lanzamiento.

+2

Espero que hayas hecho un informe de error :) – n3rd

+2

Guau, buena investigación. – GManNickG

+1

Error informado en Microsoft Connect. https://connect.microsoft.com/VisualStudio Error # 475447. –

Respuesta

4

try/catch y vuelva a intentarlo un milisegundo más tarde parece casi lo único que puede hacer hasta que se resuelva este error.

+0

Quizás. Pero tome el caso de ConcurrentQueue.TryDequeue. Ese método no debe arrojar excepciones en absoluto. Ahora tengo que ajustar todas las llamadas a TryDequeue en un bloque try/catch. ¿Y el código que no sé usa Random? –

+0

Mientras en el fondo de las bibliotecas del sistema haya un error que haga que se emitan excepciones cuando nunca debería haberlo, ¿qué otra cosa puede hacer con otro código fuera de su control, al que no tiene fuentes y que PUEDE llamar al lib del sistema en cuestión? A menos que pueda cambiar a una pila de código abierto, donde podría corregir los errores una vez que los encuentre, inevitablemente estará a merced del proveedor de código propietario. try/catch es casi lo único que puedes hacer, y definitivamente no es perfecto, pero, ¿qué más? –

Cuestiones relacionadas