これが同一のVMで起こる唯一の方法は、CPUがステージングマシン上のCPUとプロダクションマシンで異なる場合です。たとえば、 Gabe は、 zdan のコメントに尋ねました。 com/questions/7920595 /明示的なキャスティング - 二重からintの異なる結果/ 7921005#7921005 ">彼の答え。
So specifically as to what is going on. For machines that support SSE2, the cvttsd2si
instruction is used by .NET to convert the double into an int, where overflow is mapped to 0x80000000 (Int.MinValue). On machines w/o SSE2 support, I could only look at the Rotor sources, and in jithelpers.cpp, it simply casts the double to an int32 - which w/o SSE2 on VC10 C++, ends up returning the value in the lower 32 bits so the value passed to wait should be 1566804069 (0x5D638865) as you saw in the immediate window.
CPUが異なっていて、SSE2をサポートしていないマシンにコードを変更しないで "修正"しなければなりません。実稼働サーバーのCPUとステージングサーバーを確認するには、 SSE2 wikipediaの項目を参照してください。運が良ければ、サーバーのBIOS(またはVMの設定/ BIOS)で無効にすることができます。
あなたが大胆であれば、ILにパッチを当てて問題を修正することができます。コードが本当に望んでいたのはタイムアウトとして-1です。これは "永遠に待ってください"です。 ilasmとildasmを使用することで、ソースなしで修正できるかもしれません(私はこれを変更できないと仮定しています)。私は、このプログラムをILに組み込み、ILを編集し、最後に ilasm test.il/exe
というテストプログラムを作成しました。/code>を使用して新しいアセンブリを作成します。以下は私のイリノイがどのように見えたか、どうやってそれを修正したかです。
// bad code
// var t = TimeSpan.MaxValue;
IL_0008: call instance float64System.TimeSpan::get_TotalMilliseconds()
// int x = (int)t.TotalMilliseconds;
IL_000D: conv.i4 //This is the line that becomes cvttsd2si when jitted
IL_000E: stloc.2
// wh.WaitOne(x);
IL_000F: ldloc.0
IL_0010: ldloc.2
IL_0011: callvirt instance bool System.Threading.WaitHandle::WaitOne(int32)
この問題を解決するには、Wait oneを呼び出す前にx(ここでは位置2)を-1で再ロードします。
// fixed code
// var t = TimeSpan.MaxValue;
IL_0008: call instance float64System.TimeSpan::get_TotalMilliseconds()
// int x = (int)t.TotalMilliseconds;
IL_000D: conv.i4 //This is the line that becomes cvttsd2si when jitted
IL_000E: stloc.2
// x = -1;//Fix by forcing x to -1 (infinite timeout)
ldc.i4.m1 //push a -1
stloc.2 //pop and store it in 'x'
// wh.WaitOne(x);
IL_000F: ldloc.0
IL_0010: ldloc.2
IL_0011: callvirt instance bool System.Threading.WaitHandle::WaitOne(int32)
この場合、 'x'はローカル#2であることに注意してください - メソッドの一番上にあるILは正しい#を与えるので、stloc.2の2は#xが割り当てられているものに変更する必要があります。私の例ではラベルIL_0010のWaitOneを呼び出す直前のldloc命令の#にマッチします。