Glibc说fclose()/ fopen()/ fprintf()/ ftell()是线程安全的。但是当一个线程正在写入或读取文件而另一个线程正在关闭文件时会发生什么?
说我的功能看起来像这样
FILE * f; //f is opened when program starts
int log(char * str)
{
fprintf(f, "%s", str);
if (ftell(f) > SIZE_LIMIT) {
pthread_mutex_lock(&mutex);
if (ftell(f) > SIZE_LIMIT) {
fclose(f);
rename(OLD_PATH, NEW_PATH);
f = open(OLD_PATH, "a");
}
pthread_mutex_unlock(&mutex);
}
}
多个线程使用此函数写入文件。它是否安全,即没碰撞?请注意函数返回错误很好,我的实验表明程序间歇性崩溃。
编辑: 1.正如@ 2501所指出的那样,“在关联文件关闭后,指向FILE对象的指针的值是不确定的”,这解释了间歇性的崩溃。 如果我使用freopen重写代码怎么办?
pthread_mutex_lock(&mutex);
if (ftell(f) > SIZE_LIMIT) {
rename(OLD_PATH, NEW_PATH);
f = freopen(OLD_PATH, "a", f);
}
pthread_mutex_unlock(&mutex);
答案 0 :(得分:3)
每个函数都锁定与FILE*
关联的互斥锁。因此,对于特定的FILE*
对象,这些函数是“原子的”。但是一旦FILE*
对象关闭,它就无效使用。因此,如果FILE*
被关闭而另一个线程尝试使用已关闭的FILE*
,则由于尝试写入已关闭的文件而导致失败。
请注意,除了在不与其他线程同步的情况下更改f
变量时,您可能会遇到任何数据争用。 (从我们看到的代码片段来看,目前尚不清楚是否有比赛,但我猜可能存在)。
答案 1 :(得分:2)
使用fclose关闭流后,FILE
指针的值是不确定的。这意味着使用它会导致未定义的行为。
7.21.3档案
- ...指向FILE对象的指针的值是 关联文件关闭后不确定...
醇>
由于fclf调用可能在fclose()和open()之间的时间内由其他线程发生,因此当指针f
的值不确定时,行为或代码是未定义的。
要定义代码,fprintf调用以及使用指针的任何其他调用也应该由互斥锁锁定。