使用FFTW进行线程分段错误

时间:2017-10-26 22:51:58

标签: c pthreads fftw

我们在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);  
}

以&#39; w&#39;开头的变量是模块静态变量,LEN_BUFFER是超大的样本数。 谢谢大家的帮助!!

1 个答案:

答案 0 :(得分:0)

这是我的第一个涉及线程的项目,而且我的同事也没有很好的经验,所以我们没有考虑过几个问题。第一个是DETACHABLE和JOINABLE之间的区别:我们的应用程序不必等待线程完成;事实上,这是引导我们进行线程化的问题(主要是等待很长时间才能完成FFT,而这并不是必需的)。我的SW的先前版本是默认的,可加入的,因此分配给该线程的资源从未是免费的。我们没有考虑的第二点是生成线程需要额外的资源。在我的SW的先前版本中,每次必须计算FFT时都生成一个线程;在我们的应用程序中,这大约每10秒或更长时间附加一次,因此显然不重要;而且最快的是FFT开始,用于FFT的数据越少(这是一个很长的故事,但我们可以这样总结);最后,使用互斥和算法的逻辑显然保护了共享资源(同时从线程和主要使用共享资源是不太可能的)。不幸的是,线程生成,经过几个周期使内存饱和(我们不是在PC上工作,而是在一个简单的微处理器上......),这就是分段错误的起源,所以我相信。

我已经用这种方式解决了这个问题:FFT线程是在应用程序启动时生成的,因此它只与主线程一起生成一个线程。在线程内是一个无限循环,周期性地(当前比主循环快4倍)检查指示FFT请求的共享变量:如果为真,则线程在本地读取和复制共享存储器,这些存储器包含FFT输入和其他必要的参数。在处理结束时,输出保存在共享存储器中,另一个标志设置为指示fft可用的主循环。每个共享数据都使用互斥锁访问R / W,包括线程和主数据,并且只有线程使用的数据由互斥锁控制。线程生成为可拆卸而没有任何杀戮或退出,因为线程必须与主要“永远”共存。昨天这个SW运行了几个小时没有问题(我已经手动停止)以及压力条件。