是什么在背后更改我的浮点控制字?
我有一个32位的Windows应用程序,主要是用Delphi写的,它用8087浮点处理器进行浮点数的数值模拟。最近,我添加了一个功能,可以通过python2x.dll链接外部的Python代码。这个新功能导致了一些非常奇怪的行为。
这个应用程序有一个批处理模式,可以同时进行多个模拟,以利用多核架构的优势。一旦执行了Python代码,我就开始注意到不同线程中的8087控制字发生了变化。我仔细检查过,发现即使是从未调用过Python DLL的线程,控制字也发生了变化。
我知道这听起来很不可思议,但我发现有一些机制可以导致这种行为。我了解了一些信号的概念。我最开始猜测是Python DLL设置了全局的信号处理器(通过调用signal()
),这些信号处理器可能会改变控制字。例如,一个与Python代码无关的线程可能会引发SIGFPE
信号,从而修改控制字。
不过,我逐渐得出结论,signal()
并不是这个机制。我安排在启动时执行Python代码,然后把信号处理器设置回SIG_DFL
,接着开始模拟。但控制字的变化依然发生。
我最后的问题是,有没有人知道还有其他机制可以以这种方式改变控制字。我在寻找中断、APC等机制!
更新
控制字被改成了0x037F
,这是Intel的默认值,而与MSVC/Windows的默认值0x027F
不同。我猜测可能是某个地方调用了FPINIT
。
我还发现了Py_InitializeEx
,这个函数允许调用者阻止Python设置信号处理器。即使我使用这种初始化方法,控制字的变化仍然发生,所以我更加确信这不是问题的根源。
3 个回答
我遇到过这样一个情况,就是默认打印机的驱动程序在我的电脑上改变了某个控制字。当我换了默认打印机,这个问题就解决了。
为了避免这个问题,我在合适的地方把控制字设置回默认值,使用了这个代码:
_control87(_CW_DEFAULT, _CW_DEFAULT);
我还在一个客户的所有机器上看到过同样的问题,他们的电脑上安装了诺顿安全2011,但在修复了打印机驱动程序后,问题就消失了,所以我不太确定诺顿是否真的是问题的根源。
举个例子,调用 DllMain
函数时,如果带上 DLL_THREAD_ATTACH
这个标志,可以参考这个链接:msdn
更新
我找到一个类似问题的链接 - DLL加载会影响新线程的FPU控制字。不过,是关于在 DLL 加载后创建的线程。