2014-12-04 5 views
8

Per giorni ho difficoltà (ma invano) con le maschere di eccezione.Eccezioni di mascheramento in Delphi

Ho sviluppato un'applicazione che esegue calcoli in virgola mobile su centinaia di migliaia di record. Ovviamente il codice deve essere in grado di gestire le eccezioni, in particolare quelle relative ai calcoli in virgola mobile: Overflow, ZeroDivide, ecc.

L'applicazione viene eseguita correttamente in Windows 7 (32 bit o 64 bit) con molti tipi diversi di processori, se un errore si verifica che la condizione sia gestita correttamente, viene sollevata un'eccezione e il record viene scartato.

Sfortunatamente, i problemi iniziano quando lancio l'applicazione esattamente dove è previsto l'esecuzione: su un server dedicato con CPU Intel Xeon E5-2640 v2 e Windows Server 2003 R2. Qui le eccezioni non vengono sollevate: i record con errori non vengono scartati e quindi i risultati sono inquinati da questi valori numerici con i quali la macchina raffigura +INF o -INF.

Il problema è che sul server le impostazioni predefinite del mascheramento dell'errore sono diverse da quelle che troviamo in Windows 7. In particolare, chiamando la procedura GetExceptionMask sul server di default trovo exZeroDivide mentre se chiamando GetExceptionMask su Windows 7 questa eccezione non è mascherata. Il risultato è quello che ho detto: eseguendo l'applicazione sul server queste eccezioni non vengono risolte ma gestite dal processore che restituisce valori estremi e "inquinanti" numerici.

Ok, non fatevi prendere dal panico, dico, basta chiamare (vale a dire in una sezione di inizializzazione) SetExceptionMask escluso exZeroDivide, ma non funziona. O meglio, anche se appena dopo aver chiamato SetExceptionMask l'eccezione exZeroDivide non è più mascherata, quando viene eseguito il codice con calcoli in virgola mobile l'insieme TArithmeticExceptionMask restituito da GetExceptionMask contiene ancora exZeroDivide e quindi se si verifica un errore l'eccezione non viene sollevata.

Qualcuno può dirmi qual è il modo corretto per chiamare SetExceptionMask?

Qual è il motivo per cui l'impostazione predefinita di mascheratura può essere diversa da un computer e un'altra? il sistema operativo o il tipo di processore?

Grazie.

+2

Questa è una buona descrizione, ma puoi pubblicare qualche codice di esempio che genera un'eccezione e un esempio per mostrare come stai cercando di gestire il mascheramento? Ciò renderà molto più facile per noi aiutarvi a trovare una soluzione. :) –

+0

Sono d'accordo, difficile da dire senza vedere come stai facendo questo. Suggerisco di avviare una nuovissima applicazione di test che replichi questo comportamento e condivida quel codice con noi. –

+1

Sembra che qualcosa venga iniettato nel tuo processo su Server 2003 - antivirus, global hook, altra utilità di monitoraggio del sistema? - che imposta la parola di flag FP con valori errati. –

risposta

4

La causa normale di questo è che si chiama codice di terze parti che cancella le maschere. Potrebbe trattarsi di una libreria che stai utilizzando consapevolmente ma più probabilmente è qualcosa che non sei particolarmente consapevole di chiamare. Un esempio comune di questo è driver di stampa. Questi sono noti per la modifica dei flag di controllo in virgola mobile.

Il passaggio successivo è identificare quella parte del codice che modifica i flag di controllo. Ti suggerisco di aggiungere la registrazione di traccia di debug. Le chiamate a OutputDebugString sono sufficienti, ma è consigliabile utilizzare una libreria di registrazione più avanzata. Registrare lo stato dei flag di controllo mentre il programma viene eseguito. Avrai bisogno di alcuni cicli per aggiungere chiamate di registrazione, eseguire, leggere il registro, prima di poter individuare il colpevole. Una volta trovato il codice esterno che cambia i flag, assicurati di ripristinarli dopo l'esecuzione di quel codice esterno.

Questa è un'area difficile che ho paura. Non è facile avere ragione. Il codice esterno a volte suona veloce e lento con i flag di controllo come se quel codice fosse l'unico codice esistente. L'RTL Delphi non è il massimo nella gestione dei flag di controllo. Forse non è noto che Set8087CW non sia protetto da thread, ad esempio.

Ho personalmente affrontato le tue difficoltà con la mia app in virgola mobile. Ma dovresti essere in grado di risolvere questi problemi. In bocca al lupo!