我遇到了从最终无效的加法和乘法返回的浮点值的问题。
背景:我在 Visual Studio 多线程环境中使用 Speex。而在某个时刻,通常在音频编码和解码 1 或 2 分钟后,我的解码信号完全变成了 Nan。我认为我的问题与该线程中讨论的相同(Speex on windows, audio cut out),但我在这个问题上挖得更深一些。
情况:我修改了 libspeex 的一部分以放置一些调试代码,这就是我所拥有的(我在这里扩展了一些宏,我知道有些部分是多余的)。
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
第一个奇怪的行为是a1和a2计算正确的值,而mem[j]没有。第二个奇怪的事情:如果我尝试重新执行对mem[j]语句的影响(我知道这可能会导致意外结果,但它仍然为调试目的提供了提示),那么影响到mem[j]的值是期望值:同a1和a2。
我确实检查了明显的:
- 此代码部分受互斥锁保护:其他线程不可能损坏内存。
- 所有浮点值都是有效的、有限的,加法和乘法的结果应该在浮点数的范围内。
- 所有数组索引都在其各自数组的范围内。
如果没有其他线程在运行,问题似乎不会出现。
- 本线程:音频解码线程。
- 音频编码线程。
- 一些网络套接字线程...
它是大型软件的一部分,但解码部分确实受到适当互斥锁的保护,不受其他部分的影响。
所以看起来好像在浮点计算中间发生了上下文切换,并且之后它无法恢复上下文。但很难相信会发生如此糟糕的事情。
我听说在多线程中使用浮点不一致,但它应该只影响最不重要的部分,不会产生 Nan 值。
有没有人见过这样的行为?你是怎么解决的?