Turli natijalar bilan juftlikdan int ga oshkor qilish

Biz asosan buni amalga oshiradigan API foydalanayapmiz

var t = TimeSpan.MaxValue;
int x = (int)t.TotalMilliseconds;

x, System.Threading.WaitHandle.WaitOne (int) ga o'tishi bilan yakunlanadi.

Muammo shundaki, bu kod bizning dev va ishlaydigan muhitda ishlay boshlaganda, u xato qilmaydi, ammo ishlab chiqarishda ishlayotganida u:

Exception: System.ArgumentOutOfRangeException
Message: Number must be either non-negative and less than or equal to Int32.MaxValue or -1.
Parameter name: millisecondsTimeout

X = -2147483648 (int.MinValue) natijasini oddiy bir konsol ilovasida (ikkala x86 va x64) sinab ko'rsangiz, darhol oynada kodni ishga tushirganimda x = 1566804069 ni olaman.

Nima bo'lyapti o'zi?

Eslatma: bosqichma-bosqich va ishlab chiqarish bitta VM dan klonlanadi, shuning uchun ular o'rtasida farq yo'q

THIS IS CODE THAT WE CANNOT CHANGE! Otherwise I wouldn't be asking this question.

3
@Tony Menda etarli ma'lumot yo'q, shuning uchun men e'lon qildim. Juda g'alati. Men xato haqida hisobot yubordim. Biz ushbu APIni ishlatish uchun yagona odamni yaratdik, shuning uchun hech kim bu haqda xabar qilmaganida g'aroyib narsa bor, lekin bu noto'g'ri kod.
qo'shib qo'ydi muallif Dustin Davis, manba
@Ramhound, savol shunday deydi: "UShBU biz o'zgartirishga qodir emas, bu kod, aks holda men bu savolni so'ramagan bo'lardim".
qo'shib qo'ydi muallif phoog, manba
Men bu sahifani kamida 15 daqiqa oldin ochganimda o'sha erda bo'lganman.
qo'shib qo'ydi muallif phoog, manba
@Ramhound OK, ammo sharhingizni o'qiyotganda sizning sharhingiz bir necha daqiqa oldin qo'shilgani ko'rinib qoldi. Sharhlaringizni o'chirib tashlaysizmi va ularni qayta yuborasizmi? Vaqti-vaqti bilan bog'liq bo'lgan narsalar haqida gapirganda, buni qilish juda ham bosh karıştırıcı. Misol uchun, 6 daqiqa oldin javob bergan sharh 2 daqiqa oldin yuborilgan ko'rinadi.
qo'shib qo'ydi muallif phoog, manba
@Tony no, agar tekshirilsa bu ortiqcha istisno bo'lishi mumkin; ko'rsatilgan istisno yoki ni ko'rsatadi, chunki vaqt belgilanmagan yoki oraliq boshlanishi uchun salbiy.
qo'shib qo'ydi muallif Marc Gravell, manba
checked va boshqalar checked bo'lsa, albatta, xato bo'ladi, lekin turli xatosi ( OverflowException kodi>)
qo'shib qo'ydi muallif Marc Gravell, manba
@Dustin, u ishlamaydi; maksimal vaqt 10,675,199 kun; Int.MaxValue, millisekundlarda 25 kun. Bunga mos kelmaydi! -
qo'shib qo'ydi muallif Marc Gravell, manba
VM ikkala tizim uchun ham bir xil bo'lsa-da, asosiy apparat haqida nima deyish mumkin? Turli xil CPU ishlatishadimi?
qo'shib qo'ydi muallif Gabe, manba
Ikki xil natijaga erishganingiz sababli, o'tkazish translyatsiyalaringiz ko'payadi yoki Int64-ga yozing
qo'shib qo'ydi muallif Emmanuel N, manba
Bir soniya kutib turing, konsol ilovasini yaratganingizdan so'ng u ishlaydi? Lekin siz ham salbiy qadriyatdan o'tayotganingizni aytdingiz. Sizning test konsolingiz dasturi WaitOne() ni salbiy qiymatga ega deb atayapsizmi va istisno qilmadingizmi?
qo'shib qo'ydi muallif Dylan Smith, manba
Sharhlarimni o'chirib tashladim.
qo'shib qo'ydi muallif Security Hound, manba
@phoog - Yaqinda uni qo'shib qo'ydi.
qo'shib qo'ydi muallif Security Hound, manba
Fikrlarimni o'chirib tashladim va mumkin bo'lgan tuzatish bilan javob qo'shdim.
qo'shib qo'ydi muallif Tony Lee, manba
@DustinDavis - Menimcha, Gabe to'g'ri savol so'radi - Intel SSE2 ishlab chiqarish tizimini qo'llab-quvvatlayaptimi? Mashinamda, cvttsd2si (SSE2 talab qilinadi), Int.MinValue ni ishlab chiqaradigan aylantirish uchun ishlatiladi.
qo'shib qo'ydi muallif Tony Lee, manba
@Marc - men sekinlashyapman. Menimcha, bu savolda etarli ma'lumot yo'q.
qo'shib qo'ydi muallif Tony Lee, manba

4 javoblar

TimeSpan.MaxValue.TotalMilliseconds - bu Int32.MaxValue (2147483647) dan katta bo'lgan 922337203685477ga teng bo'lgan er-xotin. Bu holda quyida nima qilish kerakligi amaliyot (texnik jihatdan undefined Quyidagi @ phoog ning sharhini ko'ring) va ehtimol CPUga bog'liq bo'ladi, bu sizning farqlaringizni tushuntirishi mumkin ko'rish.

Bir holda, to'qimalarining System.Threading.WaitHandle.WaitOne (int) uchun qabul qilinishi mumkin bo'lgan qiymatga olib keladi va boshqa holatda emas.

Bu siz foydalanadigan kutubxonada xatolik kabi ko'rinadi. Agar TimeSpan-ni argument sifatida qabul qiladigan WaitOne ortiqcha yuk bo'lsa, shuning uchun ulardan nima uchun foydalanmasliklarini bilmayman. Agar siz kutubxonani o'zgartira olmasangiz, u holda siz omadsizsiz.

4
qo'shib qo'ydi
Ha, bu xato. Juda bezovta qiluvchi.
qo'shib qo'ydi muallif Dustin Davis, manba
@MarcGravell, shuningdek, ECMA 334 da "amalga oshirishga xos" emas, lekin aniqlanmagan: tekshirilmagan kontekstda konversion har doim muvaffaqiyatli bo'ladi va quyidagicha davom etadi. • Qiymati eng yaqin integral qiymatiga nolga yaqinlashadi. Agar ushbu integral qiymat maqsad turiga kirsa, bu qiymat o'tkazishning natijasidir. • Aks holda, ayirboshlash natijasi maqsad turining aniqlanmagan qiymati.
qo'shib qo'ydi muallif phoog, manba
@Marc Gravell ECMA 335, partition III, 3.27 conversion - data conversion "Agar to'lqinli suzuvchi nuqta turini butun songa o'zgartirsa yoki suzuvchi nuqta qiymati butun songa aylantirilsa NaN qaytarilgan qiymat aniqlanmagan. "
qo'shib qo'ydi muallif phoog, manba
@phoog aaahhh, TotalMilliseconds - bu double ! mening aybim; Ha, ha. Buni long deb o'yladim, u holda bu qo'shimcha bitlarni tuzatardi. Lekin ha, double uchun mantiqiydir.
qo'shib qo'ydi muallif Marc Gravell, manba
Amaliyotga xos bo'lganiga aminmisiz? boshqa operatsiyalar uchun xatti-harakatlar (qo'shimcha, ko'paytirish, va hokazo) to'liq toshqin sharoitida aniqlanadi (belgilanmagan va boshqalar tekshirilmagan) - toraygan konvertatsiya emas, balki sifatiga ega bo'lishi g'alati.
qo'shib qo'ydi muallif Marc Gravell, manba

Bunga o'xshash VM bilan sodir bo'lishi mumkin bo'lgan yagona usul - agar protsessor CPU dan ishlab chiqarish mashinasida turli xil bo'lsa, - Gabe < zdan ni so'radi. MAQOMOTI/savollar/7920595/turli-natijalar bilan ikki marta-ochiq-oydinlashtirilgan/7921005 # 7921005 "> uning javobiga asoslangan.

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.

CPUlar farq qiladi va kodni o'zgartirmaydigan "tuzatish" mashinalarni SSE2 ni qo'llab-quvvatlamaydigan biror narsaga o'zgartirishdir. Ishlab chiqarish serverining protsessorini versiya serveriga qarshi tekshirish uchun SSE2 wikipedia yozuviga qarang. Agar omadingiz bo'lsa, balki serveringizning bios (yoki VMs config/bios) da o'chirib qo'yilishi mumkin.

Agar siz jur'at qilsangiz, muammoni bartaraf etish uchun IL-ni yamashni sinab ko'rishingiz mumkin - kodni chindan ham istagan narsa - "kutib turing" deb ataladigan vaqt tugashi. Ilasm va ildasmni qo'llash orqali siz uni yo'qotishingiz mumkin (buni siz o'zgartira olmaysiz deb hisoblayman). Men ushbu dasturni muvaffaqiyatli sinov dasturida - IL kodiga ilova qilish uchun test kodi - test.exe /out=test.il ni ishlab chiqdim, ILni tahrir qildim va nihoyat ilasm test.il/exe yangi birlashma yaratish uchun. Quyida mening IL-ga o'xshagan va uni qanday tuzatganim haqida gap boradi.

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

Tuzatish - kutishdan oldin x (2-joy: bu yerda) -1 bilan qayta tiklash

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

Shuni esda tutingki, 'x' lokal # 2 - IL ning yuqori qismidagi IL sizni to'g'ri beradi # stloc.2 ning 2-sonini o'zgartirish kerak, chunki # x tayinlangan bo'lsa, namunadagi IL-0010 yorlig'ida WaitOne-ni chaqirishdan oldin ldloc ko'rsatmasiga # raqamiga mos kelishi kerak.

4
qo'shib qo'ydi
Men sizning harakatingiz uchun javob beraman. 1) xatolarni xabar qildim va ularni tuzatishga harakat qilmoqdalar va yangi versiya chiqqandan keyin menga xabar beradilar 2) Men PostSharpni Milliseconds mulkini tutgan tomonni qo'llash uchun ishlatdim va uni tegishli qiymatga almashtirdim (Fancy way nimani taklif qilsangiz, shuni qiling). Lekin siz ajoyib echimlarni taqdim etdingiz.
qo'shib qo'ydi muallif Dustin Davis, manba

Sizning ishlashingiz turli tizimlar uchun nima uchun turli xil natijalarga erishganingiz sababli toshib ketadi. Buning o'rniga uzoq vaqt foydalaning

  var t = TimeSpan.MaxValue;
  long x = (long)t.TotalMilliseconds;
0
qo'shib qo'ydi
Iltimos, REREAD savoliga javob bering, bu APIni iste'mol qilyapmiz, shuning uchun uni o'zgartira olmaymiz, aks holda men bu savolni bera olmayman.
qo'shib qo'ydi muallif Dustin Davis, manba
Yo'q, to'g'rilash ishi faqatgina WaitOne (-1) deb chaqiradi, lekin OP bu ishni qilolmaydi, chunki u faqat atrof-muhit nazorati ostida emas .
qo'shib qo'ydi muallif Gabe, manba

TimeSpan.MaxValue, WaitOne() ga o'tish uchun juda katta qiymat bo'lgan Int64.MaxValue uchun tengdir. Agar katta qiymatni qabul qilmoqchi bo'lsangiz, faqat Int32.MaxValue dan foydalaning.

0
qo'shib qo'ydi
Kodni ILSpy-dan foydalanib ko'rishim mumkin. wiki.sharpdevelop.net/ILSpy.ashx Men kodni tuzatishni o'ylamayman, men Nima uchun u ikki tizimda ishlashini bilmoqchi bo'lsak, boshqa emas.
qo'shib qo'ydi muallif Dustin Davis, manba
Bu o'zgarmas kod emas, javobingiz noto'g'ri.
qo'shib qo'ydi muallif Dustin Davis, manba
Men buni olmadim, sizda shovqin bo'lgan kod bor, lekin uni o'zgartira olmaysizmi? Buni qanday hal qilishni kutmoqdasiz?
qo'shib qo'ydi muallif Dylan Smith, manba