c - C 多线程环境中的浮点损坏

标签 c multithreading floating-point

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

背景: 我在 Visual Studio 多线程环境中使用 Speex。在某个时刻,通常在音频编码和解码 1 或 2 分钟后,我的解码信号完全变成了 Nan。我认为我的问题与此线程( Speex on windows, audio cutting 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 值。

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

最佳答案

问题:

  • 所有多余的 Actor 阵容是怎么回事?
  • den[j]nyi 的值是多少?

除此之外,合理的可能性是同一线程上的另一个计算要么溢出了浮点堆栈,要么使用了 MMX 指令,但在放弃控制之前未能发出 emms 指令(或者这些条件将导致原本无可争议的浮点计算产生 NaN 结果)。首先检查故障状态下的 x87 状态字,以确认或排除这些可能性。

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

关于c - C 多线程环境中的浮点损坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11689172/

相关文章:

c++ - 如何从 uint8_t 数组中提取不同大小的值?

c - printf 函数如何处理整数?

c - 如何写入管道叉?

java - 如何逐步执行所有线程

c# - 线程同步 : shared resources and actions with different resource number demand

c++ - 80 位 float 和次正规数

c - 将以16为底的数字转换为以2为底的数字并求和

java - 如何构建分布式 Java 应用程序?

php - MYSQL无法选取点间距离(lat,lng)=0的记录

java - 将 float 格式化为 n 位小数