Әртүрлі нәтижелермен қос int to айқын құю

Біз негізінен мұны істейтін API пайдаланамыз

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

онда x аяқталады System.Threading.WaitHandle.WaitOne (int).

Мәселе мынада, бұл кодекс біздің девайамызда және сатысындағы орталарда іске қосылғанда, ол қателерді тастамайды, бірақ өндірісте жұмыс істегенде ол:

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

Мен мұны қарапайым консольдық бағдарламамен (x86 және x64) тестілеу кезінде x = -2147483648 (int.MinValue) нәтижесін, ал мен тікелей терезеде кодты іске қосқан кезде x = 1566804069 аламын.

Не болып жатыр?

Ескерту: сатылымдар мен өндіріс бірыңғай ВМ-дан клонирленген, сондықтан олардың арасындағы айырмашылықтар жоқ

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

3
@Tony Менде жеткілікті ақпарат жоқ, сондықтан мен жарияладым. Бұл өте қызық. Мен қате туралы есеп бердім. Біз осы API-ды қолдануға жалғыз адамдар шығарамыз, сондықтан ешкім бұл туралы хабарлаған жоқ, бірақ бұл дұрыс емес код.
қосылды автор Dustin Davis, көзі
@Ramhound, сұрақ былай дейді: «БҰЛ ӨЗГЕРТІЛМЕЙДІ КОДЕНДІ, әйтпесе мен бұл сұрақты қоймас едім».
қосылды автор phoog, көзі
@Ramhound бұл жерде кем дегенде 15 минут бұрын мен алғаш рет ашқан кезде болдым.
қосылды автор phoog, көзі
@Ramhound OK, бірақ сіздің пікіріңізді оқығанымда, сіздің пікіріңіз бірнеше минут бұрын қосылды деп көрінді. Сіз өз пікірлеріңізді жойып, оларды қайта жібересіз бе? Уақытқа байланысты нәрселер туралы әңгіме қозғағанда, мұны істеу өте күрделі. Мысалы, 6 минут бұрын жауап берген түсініктеме 2 минут бұрын жарияланған сияқты.
қосылды автор phoog, көзі
@Tony жоқ, егер ол тексерілген болса болса, бұл толып кетуден құтылу еді; немесе дегенді білдіреді, бұл ұзақтығы тексерілмеген болғандықтан немесе аралықта бастау үшін теріс болғанын білдіреді.
қосылды автор Marc Gravell, көзі
@Tony checked қарамастан және checked мәселе болды, ол шынымен қате еді, бірақ бұл басқа қатесі ( OverflowException код>)
қосылды автор Marc Gravell, көзі
@Dustin, ол жұмыс істемейді; ең көп уақыт 10,675,199 күн; Миллисекундтарда int.MaxValue 25 күн. Бұл дұрыс болмайды! -
қосылды автор Marc Gravell, көзі
VM екі жүйе үшін де бірдей болса да, негізгі құрал-жабдықтар туралы не деуге болады? Олар түрлі процессорларды пайдаланады ма?
қосылды автор Gabe, көзі
Сіздің түрлендіру артықшылығыңыз, неге сіз екі түрлі нәтижелер алсаңыз, ұзындықты немесе Int64 түрін жазыңыз
қосылды автор Emmanuel N, көзі
Сіз жұмыс істегенін айтқан консоль қосымшасын жасағанда, секунд күтіңіз? Бірақ сіз сондай-ақ теріс құндылықтан өтетінін айттыңыз. Сіз сынақ консол қосымшасының WaitOne() деп аталатын теріс мәнмен аталатынсыз және ол ерекшелік тастамадыңыз ба?
қосылды автор Dylan Smith, көзі
Мен түсініктемелерімді жойдым.
қосылды автор Security Hound, көзі
@phoog - Ол жақында оны қосқан.
қосылды автор Security Hound, көзі
Түсініктемелерімді жойып, ықтимал түзетумен жауапты қосылды.
қосылды автор Tony Lee, көзі
@DustinDavis - Менің ойымша, Габе дұрыс сұрақ қойды - Intel SSE2 өндіріс жүйесін қолдайды. Менің компьютерімде cvttsd2si (SSE2 талап етіледі) айырбастау үшін пайдаланылады, ол Int.MinValue шығарады.
қосылды автор Tony Lee, көзі
@Marc - Мен баяу жүремін. Менің ойымша, бұл мәселе ақпараттың жеткіліксіз екенін білдіреді.
қосылды автор Tony Lee, көзі

4 жауаптар

TimeSpan.MaxValue.TotalMilliseconds - бұл қос 932337203685477 тең, ол Int32.MaxValue (2147483647) мәнінен үлкен. Бұл жағдайда тасқынды не істейтін болады іске қосу (техникалық анықталмаған төменде @ phoog түсініктемесін қараңыз) және, мүмкін, сіздің айырмашылықтарыңызды түсіндіруі мүмкін процессорға байланысты болады көріп.

Бір жағдайда, құю System.Threading.WaitHandle.WaitOne (int) үшін қолайлы мәнге әкеледі, ал басқа жағдайда ол жоқ.

Бұл сіз қолданатын кітапханадағы қате сияқты. TimeSpan-ды дәлел ретінде қабылдайтын WaitOne жүктемесі бар, сондықтан неге оны пайдаланбағандарын білмеймін. Егер кітапхананы өзгерте алмасаңыз, онда сіз сәттілікке жетпейсіз.

4
қосылды
Иә, бұл қате. Өте тітіркендіргіш.
қосылды автор Dustin Davis, көзі
@MarcGravell, сонымен қатар, ECMA 334-де «іске асыруға тән» емес, бірақ ол анықталмаған: Тексерілмеген контексте конверсия әрдайым сәтті болады және төменде келтіріледі. • Мән ең жақын интегралды мәнге дейін нөлге дейін дөңгелектенеді. Егер бұл интегралдық мән тағайындау түрінің ауқымында болса, онда бұл мән конверсияның нәтижесі болып табылады. • Болмаса, түрлендірудің нәтижесі тағайындалған түрдің анықталмаған мәні болып табылады.
қосылды автор phoog, көзі
@Marc Gravell ECMA 335, partition III, 3.27 conv. - деректерді түрлендіру «Егер толып кету өзгермелі нүкте түрін бүтін санға түрлендірсе немесе өзгермелі нүктенің мәні бүтін санға айналдырылса, NaN қайтарылған мән анықталмады. «
қосылды автор phoog, көзі
@phoog aaahhh, TotalMilliseconds - бұл double ! менің жаман; содан кейін иә. Мен оны long деп ойладым, бұл жағдайда ол қосымша биттерді қиып алуы мүмкін. Бірақ иә, double үшін мағынасы бар.
қосылды автор Marc Gravell, көзі
Сіз іске асыруға нақты болатынына сенімдісіз бе? басқа әрекеттердің мінез-құлқы (қосымша, көбейту және т.б.) толып кету жағдайында толығымен көрсетіледі (тексерілмеген және тексерілмеген) - тарылтудың конверсиялауы емес білікті болатынын таптым.
қосылды автор Marc Gravell, көзі

Бірдей VM-мен орын алатын жалғыз әдіс - бұл процессор процессорлық станциядан өндіріс машинасында әр түрлі болған жағдайда - Габе сұрақтарға түсініктемелерде және zdan туралы сұрады. com/questions/7920595/бөлек-екі-түрлі-нәтижелер-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.

Процессорлар әртүрлі және кодты өзгертпеген «түзету» машиналарды SSE2 қолдамайтын нәрсеге ауыстыру болып табылады. Өндіріс серверінің CPU-ін сатылым серверіне қарсы тексеру үшін SSE2 wikipedia жазбасын қараңыз. Егер сіз бақытты болсаңыз, онда сіздің серверіңіздің биосында (немесе VMs config/bios) өшірілуі мүмкін.

Егер сіз батыл болсаңыз, проблеманы түзету үшін IL-ты түзетуге тырысуға болады - бұл шын мәнінде кодты күту уақыты - «мәңгілікке күте» деген -1 болды. Ilasm және ildasm пайдалану арқылы сіз оны w/o көзін түзете аласыз (бұл сіз оны өзгерте алмайсыз деп ойлаймын). Мен тестілеу бағдарламасында табысты жұмыс жасадым - ildasm test.exe /out=test.il жинақты IL-ге айналдыру үшін, IL-ны өңдеп, соңында ilasm test.il/exe жаңа жинақ жасау үшін. Төменде менің IL-ң ұқсастығы мен оны қалай түзететінім.

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

Түзету - күте тұрмас бұрын 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 тағайындалған болса, # ldloc нұсқаулығындағы # нұсқасына WaitOne үлгісін IL_0010 белгісінде қоңыраудың алдында ғана сәйкестендіру.

4
қосылды
Мен сізге күш-жігердің арқасында жауап беремін. Мен 1) қате туралы хабарлауды және олар түзетуге дайын болды және жаңа нұсқасы шыққан кезде маған хабарлауға мүмкіндік береді. 2) Мен PostSharp-ды Milliseconds-ді мүлікте ұстайтын аспекті қолдану үшін қолдандым және оны тиісті мәнге ауыстырдым (Fancy way сіз ұсынатындарды орындау). Бірақ сіз тамаша шешімді ұсындыңыз.
қосылды автор Dustin Davis, көзі

Айырбастауыңыз әртүрлі жүйелер үшін неге әртүрлі нәтижелерге қол жеткізетіндігіңізді толтырады. Оның орнына ұзақ қолданыңыз

  var t = TimeSpan.MaxValue;
  long x = (long)t.TotalMilliseconds;
0
қосылды
Сұрақ қойыңыз, бұл API-де біз тұтынып жатырмыз, сондықтан оны өзгерте алмаймыз, әйтпесе мен бұл сұрақты қоймас едім.
қосылды автор Dustin Davis, көзі
Жоқ WaitOne (-1) деп істеуге болатын түзету , бірақ ОР мұны мүмкін емес, себебі ол тек қоршаған ортаны басқаруда .
қосылды автор Gabe, көзі

TimeSpan.MaxValue Int64.MaxValue мәніне тең, ол WaitOne() файлына өтудің тым үлкен мәні болып табылады. Егер үлкен мәнді қаласаңыз Int32.MaxValue функциясын қолданыңыз.

0
қосылды
ILSpy арқылы кодты көре аламын. wiki.sharpdevelop.net/ILSpy.ashx Мен кодты түзетемін деп ойламаймын, мен Мен екі жүйеде неге жұмыс істейтінін білемін, бірақ басқа емес.
қосылды автор Dustin Davis, көзі
Бұл өзгерте алмайтын код емес, сіз жауапсыз.
қосылды автор Dustin Davis, көзі
Мен оны алмаймын, сізде кодты бұзатын, бірақ оны өзгерте алмайсыз ба? Мұны қалай түзетесіз?
қосылды автор Dylan Smith, көзі