2014-12-04 12 views
8

Od wielu dni ciężko walczę (ale na próżno) z maskami wyjątków.Maskowanie wyjątków w Delphi

Opracowałem aplikację, która wykonuje obliczenia z dużą liczbą obliczeń zmiennoprzecinkowych na setkach tysięcy rekordów. Oczywiście kod musi obsługiwać wyjątki, szczególnie te związane z obliczeniami zmiennoprzecinkowymi: Overflow, ZeroDivide, itp.

Aplikacja działa poprawnie pod Windows 7 (32bit lub 64bit) z wieloma różnymi typami procesorów, jeśli błąd występuje, gdy warunek jest prawidłowo obsługiwany, wyjątek jest zgłaszany, a rekord jest odrzucany.

Niestety, problemy pojawiają się, gdy uruchamiam aplikację w miejscu, w którym ma działać: na dedykowanym serwerze z procesorem Intel Xeon E5-2640 v2 i systemem Windows Server 2003 R2. W tym miejscu wyjątki nie zostały podniesione: zapisy z błędami nie są odrzucane, a zatem wyniki są zanieczyszczane przez te wartości liczbowe, z którymi maszyna przedstawia +INF lub .

Problemem jest to, że na serwerze ustawienia domyślne maskowania błędów różnią się od tych, które znajdziemy w Windows 7. W szczególności, wywołując procedurę GetExceptionMask na serwerze domyślnie znajdę exZeroDivide natomiast jeśli wywołanie GetExceptionMask na Windows 7 ten wyjątek nie jest maskowany. Rezultatem jest to, co powiedziałem: uruchamiając aplikację na serwerze te wyjątki nie są wywoływane, lecz przetwarzane przez procesor zwracający ekstremum i "zanieczyszczające" wartości liczbowe.

OK, nie wpadaj w panikę, mówię, po prostu dzwonisz (to jest w sekcji inicjującej) SetExceptionMask z wyjątkiem exZeroDivide, ale to nie działa. Lub lepiej, chociaż zaraz po wywołaniu SetExceptionMask wyjątek exZeroDivide nie jest już maskowany, gdy wykonywany jest kod z obliczeniami zmiennoprzecinkowymi, zbiór TArithmeticExceptionMask zwrócony przez GetExceptionMask nadal zawiera exZeroDivide, a więc w przypadku wystąpienia błędu wyjątek nie zostanie zgłoszony.

Czy ktoś może mi powiedzieć, jaki jest prawidłowy sposób wywołania SetExceptionMask?

Jaki jest powód, dla którego domyślne ustawienie maskowania może się różnić od komputera i innego? system operacyjny lub typ procesora?

Dzięki.

+2

To jest dobry opis, ale czy możesz opublikować przykładowy kod, który generuje wyjątek, i próbkę, aby pokazać, jak próbujesz uporać się z maskowaniem? To znacznie ułatwi nam znalezienie rozwiązania. :) –

+0

Zgadzam się, trudno powiedzieć, nie widząc, jak to robisz. Sugeruję uruchomienie zupełnie nowej aplikacji testowej, która powieli to zachowanie i udostępni nam ten kod. –

+1

Wygląda na to, że coś jest wprowadzane do procesu na serwerze 2003 - sprawdzanie wirusów, globalne przechwytywanie, inne narzędzie do monitorowania systemu? - który ustawia słowo flagowe FP z niepoprawnymi wartościami. –

Odpowiedz

4

Zazwyczaj powodem jest to, że wywołujesz kod strony trzeciej, który usuwa maski. Może to być biblioteka, z której świadomie korzystasz, ale bardziej prawdopodobne jest to, że nie jesteś szczególnie świadomy dzwonienia. Typowym tego przykładem są sterowniki drukarek. Są one znane ze zmiany flag kontrolnych zmiennoprzecinkowych.

Następnym krokiem jest zidentyfikowanie tej części kodu, która zmienia flagi kontrolne. Sugeruję dodanie rejestrowania śledzenia debugowania. Połączenia z numerem OutputDebugString wystarczyłyby, ale dobrze byłoby użyć bardziej zaawansowanej biblioteki rejestrowania. Zaloguj się do stanu flag kontrolnych podczas wykonywania programu. Będziesz potrzebować kilku cykli dodawania połączeń logujących, uruchamiania, czytania dziennika, zanim będziesz w stanie zlokalizować sprawcę. Po znalezieniu kodu zewnętrznego, który zmienia flagi, należy je przywrócić po wykonaniu kodu zewnętrznego.

Obawiam się, że to trudny obszar. Nie jest łatwo dojść do porządku. Kod zewnętrzny czasami gra szybko i swobodnie z flagami kontrolnymi, tak jakby ten kod był jedynym istniejącym kodem. Delphi RTL nie jest też najlepszy w obsłudze flag kontrolnych. Być może nie jest dobrze znane, że na przykład Set8087CW nie jest chroniony wątkami.

Osobiście przeszedłem przez twoje zmagania z moją własną zmiennoprzecinkową aplikacją. Ale powinieneś być w stanie rozwiązać takie problemy. Powodzenia!