【问题标题】:Thread segmentation fault using FFTW使用 FFTW 的线程分段错误
【发布时间】:2017-10-26 22:51:58
【问题描述】:

我们在 i.MX53(基于 Linux 的 SO)上有一个 C 软件,它必须计算 FFT;为此,我们采用了 FFTW 库。出于性能原因,我们决定使用单独的线程将 FFT 从主应用程序中分离出来。整个应用程序似乎可以正常工作,但一段时间后,我们在 fftwf_execute 的对应关系中出现了分段错误。我确信这一点,因为没有这个单一的指令,我们就没有分段错误。我们进行了几次尝试,但问题仍然存在。这里是线程函数的一部分:

void* vGestDiag_ThreadFFT( void* unused )
{
  Int32U idx = 0, idxI = 0, idxJ = 0, idxZ = 0, idxK = 0;
  Flo32 lfBufferAccm_chn01[LEN_BUFFER_SAMPLES];
  Flo32 lfBufferAccm_chn02[LEN_BUFFER_SAMPLES];
  Flo64 dblBufferFFT[LEN_BUFFER_SAMPLES];
  Int32U ulCntUtilSample = 0;
  float *in;
  fftwf_complex *out;
  fftwf_plan plan;
  /* other variables.... */

  /* Init */
  memset(lfBufferAccm_chn01, 0x00, LEN_BUFFER_SAMPLES*sizeof(Flo32));
  memset(lfBufferAccm_chn02, 0x00, LEN_BUFFER_SAMPLES*sizeof(Flo32));
  memset(dblBufferFFT, 0x00, LEN_BUFFER_SAMPLES*sizeof(Flo64));
  /* other local memsets .... */

  /* Inputs */
  pthread_mutex_lock(&lockIN);

  ulCntUtilSample = wulCntUtilSample;
  /* other inputs.... */    

  for (idxJ = 0; idxJ < ulCntUtilSample; idxJ++)
  {
    boBuffCirc_ReadBuffer(&wulBufferAcc01, &ulTmpValue);
    lfBufferAccm_chn01[idxJ] = (Flo32)((((Flo32)ulTmpValue - ACC_Q)/ACC_M) * ACC_U) * wlfSensAcc;

    boBuffCirc_ReadBuffer(&wulBufferAcc02, &ulTmpValue);
    lfBufferAccm_chn02[idxJ] = (Flo32)((((Flo32)ulTmpValue - ACC_Q)/ACC_M) * ACC_U) * wlfSensAcc;
  }

  pthread_mutex_unlock(&lockIN);

  /* --------- Plan FFT ------------------------- */

  in = (float*) fftwf_malloc(sizeof(float) * ulCntUtilSample);
  out = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * ulCntUtilSample);

  fftwf_plan_with_nthreads(1);
  plan = fftwf_plan_dft_r2c_1d(ulCntUtilSample, in, out, FFTW_ESTIMATE); 


  for (idxI = 0; idxI <= 1; idxI++)
  {
    switch(idxI)
    {
      case 0:
        memcpy(in, lfBufferAccm_chn01, ulCntUtilSample*sizeof(float));
        break;

      case 1:
        memcpy(in, lfBufferAccm_chn02, ulCntUtilSample*sizeof(float));
        break;

      default:
        break;
    }

    /* --------- FFT ------------------------- */

    /* EXEC */
    fftwf_execute(plan);

    /* Complex -> Real */
    for (idxZ = 0; idxZ < ulCntUtilSample; idxZ++)
    {
      dblBufferFFT[idxZ] = cabs(out[idxZ]);
    }

    /* --------- End FFT ------------------------- */

    /* Post-Processing FFT */
    /* post-processing and outputs in module static variables, within mutex */
  }

  /* DEL plan */
  fftwf_destroy_plan(plan);
  fftwf_free(in); 
  fftwf_free(out);

  /* exit */
  pthread_exit(NULL);  
}

以“w”开头的变量是模块静态变量,LEN_BUFFER 相对于样本数量而言过大。 谢谢大家帮忙!!

【问题讨论】:

  • 在您发布的代码中看不到任何内存问题。很难推测。 wulCntUtilSample 中的值是否始终存在?是否有另一个线程负责重置该值?它永远为零吗?确保您的同步是正确的。在您致电fftwf_execute 之前,我会打印出您的缓冲区大小。也许有一些先决条件。如果您正在使用优化进行编译,关闭它们以查看它是否重现可能会很有用。如果您可以获得核心转储,调试器可能会很有用。根本原因可能完全在其他地方。
  • 你为什么使用fftwf_plan_with_nthreads(1)?您是否在代码的其他地方调用了fftw_init_threads/fftw_cleanup_threads?您还分配了比输出所需更多的内存。填充dblBufferFFT 时,您正在循环未设置的内存。看起来你犯了错误,生成并提供一个最小的例子是值得的。
  • 亲爱的@mfisherkdx,感谢您的回答。很难举个例子,我们在虚拟机上使用“特殊”环境编译,然后上传到目标;通常我们在目标终端上使用 printf 进行调试...wulCntUtilSample 是一个共享目标,所以其他线程(主要线程)设置了这个变量,但我已经将它包含在一个互斥锁中。此外,仅当变量大于 0 时才启动此线程。尊重优化,我没有使用任何特别的东西:CFLAGS=-g -c -Wall -DLINUX
  • 亲爱的@gavin-portwood,感谢您的回答。 fftw_init_threads 在应用程序的初始化中使用(仅一次),而我没有使用 fftw_cleanup_threads。 Respect fftwf_plan_with_nthreads(1) 设置为 1 以备将来使用,实际上我对使用 FFTW 特定线程没有真正的兴趣(我们正在单核处理器上开发),但我们有兴趣将耗时的 FFT 例程与主程序分开.尊重内存,你是对的,为了避免共享内存和复合操作的问题,我使用了很多线程本地内存,但是初始化了。

标签: c pthreads fftw


【解决方案1】:

这是我第一个涉及线程的项目,我的同事也没有很好的经验,所以我们没有考虑几个问题。第一个是 DETACHABLE 和 JOINABLE 之间的区别:我们的应用程序不必等待线程完成;确实这是导致我们进入线程的问题(主线程等待 FFT 完成很长时间,虽然这不是必需的)。我的 SW 的早期版本是默认的、可连接的,因此分配给线程的资源永远不会空闲。我们没有考虑的第二点是生成线程需要额外的资源。在我的 SW 的先前版本中,每次必须计算 FFT 时都会生成一个线程;在我们的应用程序中,大约每 10 秒或更长时间添加一次,因此显然不是关键;此外,最快的是 FFT 开始,用于 FFT 的数据越少(说来话长,但我们可以总结一下);最后,互斥锁的使用和算法的逻辑显然保护了共享资源(从线程和主线程同时使用共享资源的可能性很小)。不幸的是,线程生成,在几个周期后使内存饱和(我们不是在 PC 上工作,而是在一个简单的微处理器上工作......),这就是分段错误的根源,所以我相信。

我是这样解决问题的:FFT线程是在应用程序启动时生成的,所以只生成一个线程,连同main.线程内是一个无限循环,它定期(目前比主循环快 4 倍)检查指示 FFT 请求的共享变量:如果为真,则线程在本地读取并复制包含 FFT 输入的共享内存和其他必需的参数。在处理结束时,输出保存在共享内存中,并设置另一个标志以指示 fft 可用的主循环。在线程和主线程中,每个共享数据都使用互斥锁进行 R/W 访问,并且只有线程使用的数据由互斥锁控制。线程被生成为可分离的,没有任何终止或退出,因为线程必须与主线程“永远”一起存在。昨天这个 SW 已经运行了几个小时没有问题(我已经手动停止了)并且还在压力条件下。

【讨论】:

  • 在 Apache Spark(使用 JNI)中集成 FFTW3 时遇到问题。如果我在集群模式下使用每个节点的单个核心或单台机器(本地模式)中的单个核心来执行我的应用程序,那么一切正常。但是,如果我通过每台机器使用两个或更多内核来执行我的应用程序,我会发现这个问题:SIGSEGV (0xb) at pc=0x00007ff9007bc5ae, pid=27386, tid=0x00007ff91e1f1700 - 有问题的框架:C [libfftw3f.so.3+0x155ae ] fftwf_mkplan+0xe
  • 你能解释一下如何创建互斥锁吗?
  • 当然,如果可以的话。我们已经使用静态 pthread_mutex_t lockIN = PTHREAD_MUTEX_INITIALIZER 作为全局文件变量初始化了一个通用锁。然后我们使用 pthread_mutex_lock(&lockIN); 保护了可能产生访问问题的源代码部分。在该部分的开头和 pthread_mutex_unlock(&lockIN);在最后。不要夸大这些互斥锁,仅在必要时使用它们。
猜你喜欢
  • 1970-01-01
  • 2019-06-26
  • 2014-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-23
相关资源
最近更新 更多