Delphi中的异常掩盖

8
多日来我一直在苦苦挣扎(但是徒劳无功)地处理异常掩码。
我开发了一个应用程序,可以在成千上万的记录上进行重型浮点计算。显然,代码必须能够处理异常,特别是与浮点计算相关的异常:Overflow、ZeroDivide等等。
该应用程序在Windows 7(32位或64位)下以许多不同类型的处理器运行,如果出现错误,则会正确处理条件,引发异常并丢弃记录。
不幸的是,当我在一个专用服务器上启动应用程序时,问题就开始了。该服务器使用英特尔Xeon E5-2640 v2 CPU和Windows Server 2003 R2操作系统。在这里,不会引发异常:具有错误的记录不会被丢弃,因此结果会受到机器所描述的数值“+INF”或“-INF”的污染。
问题在于,在服务器上,错误掩码的默认设置与我们在Windows 7中找到的不同。特别是,在服务器上调用GetExceptionMask过程时,默认情况下我发现exZeroDivide,而在Windows 7上调用GetExceptionMask时,此异常未被屏蔽。结果就是我说的:在服务器上运行应用程序时,这些异常不会被引发,但由处理器处理,返回极端值和“污染”的数值。
好了,别惊慌,我说,你只需(即在初始化部分中)调用SetExceptionMask,排除exZeroDivide,但它无效。或者更好的是,尽管在调用SetExceptionMask后,异常exZeroDivide不再被屏蔽,但在执行带有浮点计算的代码时,由GetExceptionMask返回的设置TArithmeticExceptionMask仍包含exZeroDivide,因此如果出现错误,则不会引发异常。
有人可以告诉我调用SetExceptionMask的正确方法是什么吗?
为什么掩码默认值可能与计算机和另一个计算机不同呢?操作系统还是处理器类型?
谢谢。

2
这是一个很好的描述,但你能否发布一些生成异常的示例代码以及一个展示如何尝试处理掩码的示例?这将使我们更容易帮助您找到解决方案。 :) - Mason Wheeler
我同意,如果不看你是如何做的,很难说清楚。我建议开始一个全新的测试应用程序来复制这种行为,并与我们分享该代码。 - Jerry Dodge
1
听起来像是在Server 2003的进程中注入了某些东西 - 病毒检查器、全局钩子、其他系统监控工具?- 这会使用不正确的值设置FP标志字。 - 500 - Internal Server Error
1个回答

4
通常情况下,这是因为您在调用清除掩码的第三方代码。可能是您知道的某个库,但更有可能是您不太清楚的某些调用。一个常见的例子是打印机驱动程序。这些驱动程序以更改浮点控制标志而闻名。
接下来的步骤是确定更改控制标志的代码部分。我建议您添加调试跟踪日志记录。调用“OutputDebugString”就足够了,但您最好使用更高级的日志记录库。当程序执行时记录控制标志的状态。需要几个周期添加日志调用、运行、读取日志,才能找到罪魁祸首。一旦找到更改标志的外部代码,请确保在该外部代码执行后恢复它们。
恐怕这是一个棘手的领域。很难做到正确。外部代码确实有时会像那些代码是唯一存在的代码一样快速和松散地处理控制标志。Delphi RTL 在处理控制标志方面并不是最好的。例如,“Set8087CW”不是线程安全的,这可能不是众所周知的。
我个人也经历过自己的浮点应用程序的困境。但您应该能够解决这类问题。祝你好运!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接