Maskierung von Ausnahmen in Delphi

8

Seit Tagen kämpfe ich hart (aber vergeblich) mit den Ausnahmemasken.

Ich habe eine Anwendung entwickelt, die Berechnungen von Fließkommazahlen auf Hunderttausenden von Datensätzen durchführt. Offensichtlich muss der Code in der Lage sein, Ausnahmen zu behandeln, insbesondere solche, die sich auf Fließkommaberechnungen beziehen: Overflow, ZeroDivide, etc ..

Die Anwendung läuft korrekt unter Windows 7 (32bit oder 64bit) mit vielen verschiedenen Arten von Prozessoren, wenn ein Fehler auftritt, wird die Bedingung richtig behandelt, eine Ausnahme wird ausgelöst und der Datensatz wird verworfen.

Leider beginnen die Probleme beim Start der Anwendung nur dort, wo sie ausgeführt werden soll: auf einem dedizierten Server mit Intel Xeon E5-2640 v2 CPU und Windows Server 2003 R2. Hier werden die Ausnahmen nicht ausgelöst: Datensätze mit Fehlern werden nicht verworfen und so werden die Ergebnisse durch diese numerischen Werte, mit denen die Maschine +INF oder -INF darstellt, verschmutzt.

Das Problem ist, dass sich die Standardeinstellungen der Fehlermaskierung auf dem Server von denen unterscheiden, die wir in Windows 7 finden. Insbesondere beim Aufruf der Prozedur GetExceptionMask auf dem Server finde ich exZeroDivide beim Aufruf GetExceptionMask unter Windows 7 diese Ausnahme ist nicht maskiert. Das Ergebnis ist das, was ich gesagt habe: Beim Ausführen der Anwendung auf dem Server werden diese Ausnahmen nicht ausgelöst, sondern von dem Prozessor behandelt, der Extreme und "verschmutzende" numerische Werte zurückgibt.

Ok, keine Panik, sage ich, Sie rufen einfach an (d. h. in einem Initialisierungsabschnitt) SetExceptionMask exclusive exZeroDivide , funktioniert aber nicht. Oder besser, obwohl kurz nach dem Aufruf von SetExceptionMask die Ausnahme exZeroDivide nicht mehr maskiert wird, wenn der Code mit Gleitkommaberechnungen ausgeführt wird, enthält die von TArithmeticExceptionMask zurückgegebene Menge GetExceptionMask immer noch exZeroDivide und so, wenn ein Fehler auftritt Die Ausnahme wird nicht ausgelöst.

Kann mir jemand sagen, wie man SetExceptionMask richtig aufruft?

Aus welchem ​​Grund kann der Maskierungsstandard von einem Computer und einem anderen abweichen? das Betriebssystem oder die Art des Prozessors?

Danke.

    
Juan Bonaventura 04.12.2014, 01:13
quelle

1 Antwort

4

Der übliche Grund dafür ist, dass Sie einen Drittanbietercode aufrufen, der die Masken löscht. Es kann eine Bibliothek sein, die Sie wissentlich benutzen, aber wahrscheinlicher ist es etwas, von dem Sie nicht besonders wissen, dass es angerufen wird. Ein gängiges Beispiel hierfür sind Druckertreiber. Diese sind dafür bekannt, die Gleitkomma-Steuerflags zu ändern.

Der nächste Schritt besteht darin, den Teil des Codes zu identifizieren, der die Steuerflags ändert. Ich schlage vor, dass Sie Debug-Protokollierung hinzufügen. Aufrufe von OutputDebugString würden ausreichen, aber Sie sollten eine erweiterte Protokollierungsbibliothek verwenden. Protokollieren Sie den Status der Steuerungsflags, während Ihr Programm ausgeführt wird. Sie brauchen ein paar Zyklen zum Hinzufügen von Protokollierungsaufrufen, zum Ausführen, zum Lesen des Protokolls, bevor Sie den Täter finden können. Sobald Sie den externen Code gefunden haben, der die Flags ändert, stellen Sie sicher, dass Sie sie wiederherstellen, nachdem der externe Code ausgeführt wurde.

Dies ist ein schwieriges Gebiet, fürchte ich. Es ist nicht leicht, richtig zu kommen. Externer Code spielt manchmal schnell und locker mit den Kontrollflags, als ob dieser Code der einzige existierende Code wäre. Die Delphi-RTL ist auch nicht am besten bei der Handhabung von Kontrollflags. Es ist vielleicht nicht bekannt, dass Set8087CW beispielsweise nicht threadsafe ist.

Ich habe deine Schwierigkeiten mit meiner eigenen Gleitkomma-App selbst durchgemacht. Aber Sie sollten solche Probleme lösen können. Viel Glück!

    
David Heffernan 04.12.2014 07:13
quelle