相关文章推荐
爱笑的肉夹馍  ·  CronExpression ...·  1 年前    · 
越狱的凉面  ·  CSP ...·  1 年前    · 

fwrite fopen 阻塞线程

1 人关注

我有一个用c语言编写的多线程的Linux应用程序,在i.mx6 arm上运行。 我有一个25lc256 spi eeprom映射到文件系统中。 在驱动层面上,写的速度相对较慢,没有什么可以做的。 问题是,文件函数阻塞其他线程的时间太长了。增加usleep似乎没有帮助,看来我必须做一些不同的事情,但我不清楚要改变什么。

从一个线程调用这个函数的输出是

EEprom write
在522.000000 703.000000 705.000000中保存的EEprom 723.000000 662596.000000 1328858.000000
捕获 -EPIPE snd_pcm_prepare

With捕获 -EPIPE snd_pcm_prepare coming from the thread where the audio buffer underran because of the blocked thread, I suppose.

int SaveCurrentConfig(void) {//EEPROM
    int r = 1;
    struct timeval tvs, tv1, tv2, tv3, tv4, tv5, tv6;
    gettimeofday(&tvs, NULL);
    printf("EEprom write\n");
    pthread_mutex_lock(&eepromconfigmutex);
        char * ConfigXml = BuildXmlConfig();
        FILE * WriteConfig = fopen(ConfigPath, "w");
        if (WriteConfig == NULL) {
            MyLog("Unable to open eeprom %s\n", strerror(errno));
            r = 0;
            goto badfinish;
        gettimeofday(&tv1, NULL);
        size_t len = strlen(ConfigXml);
        unsigned short CRC = ComputeChecksum(ConfigXml, len);
        fwrite((char*) &len, 1, sizeof (size_t), WriteConfig);
        gettimeofday(&tv2, NULL);
        fwrite((char*) &CRC, 1, 2, WriteConfig);
        gettimeofday(&tv3, NULL);
        fwrite(ConfigXml, 1, strlen(ConfigXml), WriteConfig);
        gettimeofday(&tv4, NULL);
        fseek(WriteConfig, ConfigOffset2, SEEK_SET);
        fwrite((char*) &len, 1, sizeof (size_t), WriteConfig);
        fwrite((char*) &CRC, 1, 2, WriteConfig);
        fwrite(ConfigXml, 1, strlen(ConfigXml), WriteConfig);
        gettimeofday(&tv5, NULL);
        fclose(WriteConfig);
badfinish:
        free(ConfigXml);
    pthread_mutex_unlock(&eepromconfigmutex);
    gettimeofday(&tv6, NULL);
    double diff1 = time_diff(tvs, tv1);
    double diff2 = time_diff(tvs, tv2);
    double diff3 = time_diff(tvs, tv3);
    double diff4 = time_diff(tvs, tv4);
    double diff5 = time_diff(tvs, tv5);
    double diff6 = time_diff(tvs, tv6);
    printf("EEprom saved in %f  %f  %f  %f  %f  %f\n", diff1, diff2, diff3, diff4, diff5, diff6);
    return r;
    
linux
pthreads
Erik Friesen
Erik Friesen
发布于 2016-01-29
3 个回答
caf
caf
发布于 2016-01-29
已采纳
0 人赞同

如果那个调用 fclose() 的线程长时间阻塞了其他线程的运行,那么问题很可能是它在内核模式下花了大量时间在eeprom驱动代码里面,冲掉了待写的内容。

有几件事情你可以试试。

  • Ensure you're running a kernel with the PREEMPT configuration option selected. This will allow the thread to be preempted while it's running the eeprom driver code.
  • In conjunction with the first suggestion, set a higher scheduling priority for the sound thread (and/or a lower scheduling priority for the eeprom writing thread).
  • Change your code to flush the writes out to the eeprom more frequently by calling fflush() after writing a smaller block of data (you may need to also call fsync() on the underlying file descriptor).
  • 我认为这最能解释这里发生的事情。 我认为最好的选择是在用户空间中进行raw spi,而不是搞乱线程优先级。
    用户空间驱动在大约1/3的时间内完成了这一写入。
    Brian Malehorn
    Brian Malehorn
    发布于 2016-01-29
    0 人赞同

    看起来问题出在 fclose() 上。 fclose() ,但默认情况下,在文件内容被写入磁盘之前不会返回。我相信你可以用 O_NONBLOCK 强迫它提前返回,从 man 2 open

    O_NONBLOCK或O_NDELAY

       When possible, the file is opened in  nonblocking  mode.   Neither
       the  open()  nor  any subsequent operations on the file descriptor
       which is returned will cause the calling process to wait.  For the
       handling  of FIFOs (named pipes), see also fifo(7).  For a discus‐
       sion of the effect of O_NONBLOCK  in  conjunction  with  mandatory
       file locks and with file leases, see fcntl(2).
    

    你可以用这个来试试。

    int fd = open(ConfigPath, O_WRONLY | O_NONBLOCK);
    FILE * WriteConfig = fdopen(fd, "w");
        
    ron
    ron
    发布于 2016-01-29
    0 人赞同

    我想试一试

    fflush( WriteConfig );