Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C多线程环境中的浮点损坏_C_Multithreading_Floating Point - Fatal编程技术网

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

C多线程环境中的浮点损坏,c,multithreading,floating-point,C,Multithreading,Floating Point,我遇到了一个问题,从加法和乘法返回的浮点值最终无效 背景: 我正在VisualStudio多线程环境中使用Speex。在某一点上,通常经过1或2分钟的音频编码和解码后,我的解码信号会完全变为Nan。我认为我的问题与本文()中讨论的相同,但我在这个问题上做了更深入的研究 情况: 我修改了libspeex的一部分,添加了一些调试代码,下面是我所拥有的(我在这里扩展了一些宏,我知道有些部分是多余的) 第一个奇怪的行为是a1和a2计算正确的值,而mem[j]不计算。第二件奇怪的事:如果我试图重新执行对m

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

背景: 我正在VisualStudio多线程环境中使用Speex。在某一点上,通常经过1或2分钟的音频编码和解码后,我的解码信号会完全变为Nan。我认为我的问题与本文()中讨论的相同,但我在这个问题上做了更深入的研究

情况: 我修改了libspeex的一部分,添加了一些调试代码,下面是我所拥有的(我在这里扩展了一些宏,我知道有些部分是多余的)

第一个奇怪的行为是a1和a2计算正确的值,而mem[j]不计算。第二件奇怪的事:如果我试图重新执行对mem[j]的矫揉造作语句(我知道这可能会导致意外的结果,但它仍然为调试目的提供了提示),那么对mem[j]影响的值就是预期值:与a1和a2相同

我确实检查了明显的:

  • 此代码部分受互斥保护:其他线程不可能损坏内存
  • 所有浮点值都是有效的、有限的,加法和乘法的结果应该在浮点值的范围内
  • 所有数组索引都在各自数组的范围内
如果没有其他线程运行,则问题似乎不会出现

  • 此线程:音频解码线程
  • 音频编码线程
  • 一些网络套接字线程
它是一个大型软件的一部分,但是解码部分实际上是通过适当的互斥来保护的

这样,在浮点计算的中间,好像上下文切换发生了,并且它无法恢复上下文。但很难相信会有那么糟糕的事情发生

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

有人见过这样的行为吗?你是如何解决的?

问题:

  • 那些多余的演员怎么了
  • den[j]
    nyi
    的值是多少
除此之外,一个合理的可能性是,同一线程上的另一个计算要么溢出浮点堆栈,要么使用MMX指令,但在产生控制之前未能发出
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