fwrite fopen 阻塞线程
fwrite fopen blocking threads
我在 i.mx6 arm 上有一个用 c 运行 编写的多线程 linux 应用程序。我有一个映射到文件系统的 25lc256 spi eeprom。驱动程序级别的写入相对较慢,在那里可以做的事情不多。问题是文件函数阻塞其他线程的时间太长了。 usleep 添加似乎没有帮助,看来我必须做一些不同的事情,但我不清楚要改变什么。
从一个线程调用此函数的输出是
EEprom write
EEprom saved in 522.000000 703.000000 705.000000
723.000000 662596.000000 1328858.000000
Capture -EPIPE snd_pcm_prepare
我想 Capture -EPIPE snd_pcm_prepare 来自音频缓冲区由于线程阻塞而导致运行不足的线程。
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;
}
看起来问题出在 fclose()
。 fclose()
,但默认情况下,在文件内容写入磁盘之前不会 return。我相信你可以用 O_NONBLOCK
从 man 2 open
:
强制它提前到 return
O_NONBLOCK or 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");
我会尝试
fflush( WriteConfig );
就在你
之前
fclose(WriteConfig);
如果调用 fclose()
的线程长时间阻塞来自 运行 的其他线程,那么问题很可能是它在 eeprom 驱动程序代码中的内核模式下花费了大量时间,清除挂起的写入。
您可以尝试以下几种方法:
- 确保您 运行 内核选择了
PREEMPT
配置选项。这将允许线程在 运行 eeprom 驱动程序代码时被抢占。
- 结合第一个建议,为声音线程设置更高的调度优先级(and/or为eeprom写入线程设置较低的调度优先级)。
- 更改您的代码,通过在写入较小的数据块后调用
fflush()
来更频繁地刷新对 eeprom 的写入(您可能还需要在底层文件描述符上调用 fsync()
) .
我在 i.mx6 arm 上有一个用 c 运行 编写的多线程 linux 应用程序。我有一个映射到文件系统的 25lc256 spi eeprom。驱动程序级别的写入相对较慢,在那里可以做的事情不多。问题是文件函数阻塞其他线程的时间太长了。 usleep 添加似乎没有帮助,看来我必须做一些不同的事情,但我不清楚要改变什么。
从一个线程调用此函数的输出是
EEprom write
EEprom saved in 522.000000 703.000000 705.000000 723.000000 662596.000000 1328858.000000
Capture -EPIPE snd_pcm_prepare
我想 Capture -EPIPE snd_pcm_prepare 来自音频缓冲区由于线程阻塞而导致运行不足的线程。
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;
}
看起来问题出在 fclose()
。 fclose()
,但默认情况下,在文件内容写入磁盘之前不会 return。我相信你可以用 O_NONBLOCK
从 man 2 open
:
O_NONBLOCK or 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");
我会尝试
fflush( WriteConfig );
就在你
之前fclose(WriteConfig);
如果调用 fclose()
的线程长时间阻塞来自 运行 的其他线程,那么问题很可能是它在 eeprom 驱动程序代码中的内核模式下花费了大量时间,清除挂起的写入。
您可以尝试以下几种方法:
- 确保您 运行 内核选择了
PREEMPT
配置选项。这将允许线程在 运行 eeprom 驱动程序代码时被抢占。 - 结合第一个建议,为声音线程设置更高的调度优先级(and/or为eeprom写入线程设置较低的调度优先级)。
- 更改您的代码,通过在写入较小的数据块后调用
fflush()
来更频繁地刷新对 eeprom 的写入(您可能还需要在底层文件描述符上调用fsync()
) .