Glibc说fclose()/fopen()/fprintf()/fcall()是线程安全的。但是当一个线程写入或读取文件而另一个线程关闭文件时会发生什么呢?
说我有一个函数看起来像这样
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);
这些函数中的每一个都锁定了与FILE*
关联的互斥锁。因此,这些函数相对于特定的FILE*
对象是“原子的”。但是一旦FILE*
对象被关闭,它就不能使用。因此,如果FILE*
被关闭,另一个线程尝试使用该关闭的FILE*
,那么您将由于尝试写入已关闭的文件而失败。
请注意,这是除了在不与其他线程同步的情况下更改f
变量时可能发生的任何数据竞争之外的情况。(从我们看到的代码片段来看,不清楚那里是否有竞争,但我猜测可能有)。
使用foff关闭流后,FILE
指针的值是不确定的。这意味着使用它会导致未定义的行为。
7.21.3文件
由于fprintf调用可能在fclose()和open()之间的时间内由其他线程发生,因此当指针f
的值不确定时,行为或您的代码是未定义的。
为了定义代码,fprintf调用和任何其他使用指针的调用也应该被互斥锁锁定。