8

几天来,我一直在努力(但徒劳)用例外面具。

我开发了一个应用程序,可以对数十万条记录进行繁重的浮点计算。显然代码必须能够处理异常,尤其是那些与浮点计算相关的:溢出、ZeroDivide 等。

应用程序在具有许多不同类型处理器的 Windows 7(32 位或 64 位)下正确运行,如果发生错误,则正确处理条件,引发异常并丢弃记录。

不幸的是,当我在打算运行的位置启动应用程序时,问题就开始了:在具有 Intel Xeon E5-2640 v2 CPU 和 Windows Server 2003 R2 的专用服务器上。这里没有引发异常:有错误的记录不会被丢弃,因此结果会被机器描述的这些数值污染+INF或污染-INF

问题是,在服务器上,错误屏蔽的默认设置与我们在 Windows 7 中找到的设置不同。特别是,GetExceptionMask我发现默认情况下在服务器上调用该过程,exZeroDivide而如果GetExceptionMask在 Windows 7 上调用,则不会屏蔽此异常。结果就是我所说的:在服务器上运行应用程序时,这些异常不会引发,而是由处理器处理,返回极端值和“污染”数值。

好的,不要惊慌,我说,您只需调用(即在初始化部分)SetExceptionMaskexclude exZeroDivide,但不起作用。或者更好的是,虽然在调用SetExceptionMask异常 之后exZeroDivide不再被屏蔽,但当执行具有浮点计算的代码时,TArithmeticExceptionMask返回的集合GetExceptionMask仍然包含exZeroDivide,因此如果发生错误,则不会引发异常。

谁能告诉我正确的打电话方式是SetExceptionMask什么?

这就是为什么屏蔽默认值可能与计算机和另一个不同的原因?操作系统或处理器类型?

谢谢。

4

1 回答 1

4

造成这种情况的通常原因是您正在调用清除掩码的第三方代码。它可能是您有意使用的库,但更有可能是您没有特别意识到调用它的东西。一个常见的例子是打印机驱动程序。这些因更改浮点控制标志而臭名昭著。

下一步是识别更改控制标志的那部分代码。我建议您添加调试跟踪日志记录。调用OutputDebugString就足够了,但您最好使用更高级的日志库。在程序执行时记录控制标志的状态。在找到罪魁祸首之前,您需要几个周期来添加日志调用、运行、读取日志。找到更改标志的外部代码后,请确保在外部代码执行后恢复它们。

恐怕这是一个棘手的领域。做对并不容易。外部代码有时会随着控制标志快速而松散地播放,就好像该代码是唯一存在的代码一样。Delphi RTL 在处理控制标志方面也不是最好的。例如,可能不为人所知的是,Set8087CW它不是线程安全的。

我亲身经历了您与我自己的浮点应用程序的斗争。但是你应该能够解决这些问题。祝你好运!

于 2014-12-04T07:13:14.843 回答