C多线程环境中的浮点损坏
我遇到了一个问题,从加法和乘法返回的浮点值最终无效 背景: 我正在VisualStudio多线程环境中使用Speex。在某一点上,通常经过1或2分钟的音频编码和解码后,我的解码信号会完全变为Nan。我认为我的问题与本文()中讨论的相同,但我在这个问题上做了更深入的研究 情况: 我修改了libspeex的一部分,添加了一些调试代码,下面是我所拥有的(我在这里扩展了一些宏,我知道有些部分是多余的) 第一个奇怪的行为是a1和a2计算正确的值,而mem[j]不计算。第二件奇怪的事:如果我试图重新执行对mem[j]的矫揉造作语句(我知道这可能会导致意外的结果,但它仍然为调试目的提供了提示),那么对mem[j]影响的值就是预期值:与a1和a2相同 我确实检查了明显的:C多线程环境中的浮点损坏,c,multithreading,floating-point,C,Multithreading,Floating Point,我遇到了一个问题,从加法和乘法返回的浮点值最终无效 背景: 我正在VisualStudio多线程环境中使用Speex。在某一点上,通常经过1或2分钟的音频编码和解码后,我的解码信号会完全变为Nan。我认为我的问题与本文()中讨论的相同,但我在这个问题上做了更深入的研究 情况: 我修改了libspeex的一部分,添加了一些调试代码,下面是我所拥有的(我在这里扩展了一些宏,我知道有些部分是多余的) 第一个奇怪的行为是a1和a2计算正确的值,而mem[j]不计算。第二件奇怪的事:如果我试图重新执行对m
- 此代码部分受互斥保护:其他线程不可能损坏内存
- 所有浮点值都是有效的、有限的,加法和乘法的结果应该在浮点值的范围内
- 所有数组索引都在各自数组的范围内
- 此线程:音频解码线程
- 音频编码线程
- 一些网络套接字线程
这样,在浮点计算的中间,好像上下文切换发生了,并且它无法恢复上下文。但很难相信会有那么糟糕的事情发生
我听说在多线程中使用浮点不一致,但它只会影响最不重要的部分,而不会生成Nan值 有人见过这样的行为吗?你是如何解决的?问题:- 那些多余的演员怎么了
和den[j]
的值是多少nyi
emms
指令(这两种情况中的任何一种都会导致原本不受反对的浮点计算产生NaN结果)。首先检查处于故障状态的x87状态字,以确认或排除这些可能性
如果没有多个线程,问题就不会发生,这一事实使得这种解释的可能性有所降低,但到目前为止,损坏的x87状态是“否则无法解释”的最常见根源所以这三行在库中,对吗?为什么有三行计算相同的东西?为什么你还要重复计算三次?你不能存储一次并分配多次吗?这是严格可复制的吗?(是每次都在同一个地方失败,还是在不同的时间发生?)@Shahbaz a1和a2行由我添加以进行调试,并显示非重复/奇怪的行为。@Wug每次迭代不会失败,需要1到2分钟。但每次失败时,它都会在同一行代码中失败。@jslap,
j
的值是多少,测试fai的mem
的大小是多少ls?另外,您是否注意到den
并不是真正的数组?(或者复制到堆栈溢出时这是一个输入错误?)我应该在故障发生之前还是之后查看状态寄存器?我必须查看异常部分?异常位的正常值是多少?0?在故障发生后检查状态寄存器的状态。如果设置了IE和SF位(0和6),则您正在查看堆栈损坏。如果IE(位0)设置了,但SF未设置,则您的计算合法地生成了一个NaN。抱歉,延迟。我再次复制了错误,并且stat寄存器设置为0x0961。因此,是的,设置了无效操作和堆栈错误位。因此,我的堆栈已损坏。知道如何从那里继续吗?很有趣。FPU状态是线程本地的,所以这不应该更改取决于是否有其他线程正在运行(除非您的操作系统真的、真的崩溃了,在这种情况下,您可能会看到其他故障)。是否有任何代码只有在启用多线程时才运行?另一个要检查的事项是确保在生成项目时启用了缺少原型的警告;调用返回浮点值而没有原型的函数是x87堆栈损坏的最常见原因。没有缺少原型,任何地方都没有。我检查tatus在错误操作之前进行了位,它是正常的。紧接着,它设置了两个坏位:IE和SF。拆解看起来很好。如果我重置IE和SF并重复浮点操作,它会给出正确的结果,并且不会设置IE或SF。
float *mem, *den; // Arrays of finite float values
float nyi; // finite float value.
float a1, a2; // debug test variables.
...
if (!_finite(mem[j]) || !_finite(mem[j+1]))
printf("Nan\n"); // Does not reach this
a1 = ((mem[j+1])+(float)(den[j])*(float)(nyi)); // a1 == expected value
mem[j] = ((mem[j+1])+(float)(den[j])*(float)(nyi)); // mem[j] == -1.#IND
a2 = ((mem[j+1])+(float)(den[j])*(float)(nyi)); // a2 == expected value
if (!_finite(mem[j]) || !_finite(mem[j+1]))
printf("Nan\n"); // Program reach this and stops at breakpoint