2

我遇到了从最终无效的加法和乘法返回的浮点值的问题。

背景:我在 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

第一个奇怪的行为是a1a2计算正确的值,而mem[j]没有。第二个奇怪的事情:如果我尝试重新执行对mem[j]语句的影响(我知道这可能会导致意外结果,但它仍然为调试目的提供了提示),那么影响到mem[j]的值是期望值:同a1和a2。

我确实检查了明显的:

  • 此代码部分受互斥锁保护:其他线程不可能损坏内存。
  • 所有浮点值都是有效的、有限的,加法和乘法的结果应该在浮点数的范围内。
  • 所有数组索引都在其各自数组的范围内。

如果没有其他线程在运行,问题似乎不会出现。

  • 本线程:音频解码线程。
  • 音频编码线程。
  • 一些网络套接字线程...

它是大型软件的一部分,但解码部分确实受到适当互斥锁的保护,不受其他部分的影响。

所以看起来好像在浮点计算中间发生了上下文切换,并且之后它无法恢复上下文。但很难相信会发生如此糟糕的事情。

我听说在多线程中使用浮点不一致,但它应该只影响最不重要的部分,不会产生 Nan 值。

有没有人见过这样的行为?你是怎么解决的?

4

1 回答 1

2

问题:

  • 所有多余的演员是怎么回事?
  • den[j]和的值是nyi多少?

除此之外,一个合理的可能性是同一线程上的另一个计算溢出了浮点堆栈,或者使用了 MMX 指令但未能emms在产生控制权之前发出指令(这些条件中的任何一个都会导致在其他情况下无异议的浮点计算产生 NaN 结果)。首先检查故障状态下的 x87 状态字,以确认或排除这些可能性。

没有多个线程就不会发生问题的事实使得这种解释不太可能,但损坏的 x87 状态是迄今为止“否则无法解释”的 NaN 的最常见来源,应该首先排除。

于 2012-07-27T14:24:03.913 回答