Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
fclose()、fprintf()、ftell()线程仅就每个函数本身而言是安全的吗?_C_Linux - Fatal编程技术网

fclose()、fprintf()、ftell()线程仅就每个函数本身而言是安全的吗?

fclose()、fprintf()、ftell()线程仅就每个函数本身而言是安全的吗?,c,linux,C,Linux,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_loc

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所指出的,“关联文件关闭后,指向文件对象的指针的值是不确定的”,这解释了间歇性崩溃的原因。 如果我用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);

每个函数都会锁定与
文件*
关联的互斥锁。因此,对于特定的
文件*
对象,这些函数是“原子的”。但是一旦
文件*
对象关闭,它就不能使用了。因此,如果
文件*
关闭,而另一个线程尝试使用该关闭的
文件*
,那么您将由于尝试写入关闭的文件而失败


请注意,这不包括在不与其他线程同步的情况下更改
f
变量时可能发生的任何数据争用。(从我们看到的代码片段中,不清楚是否存在种族,但我猜可能存在)。

使用fclose关闭流后,
文件
指针的值不确定。这意味着使用它会导致未定义的行为

7.21.3文件

  • 。。。指向文件对象的指针的值为 关联文件关闭后不确定
  • 由于fprintf调用可能由其他线程在fclose()和open()之间发生,因此当指针
    f
    的值不确定时,行为或代码未定义


    要定义代码,fprintf调用和使用指针的任何其他调用也应被互斥锁锁定。

    关注安全的代码应检查各种I/O函数的结果。(可能是为了简化而将它们放在这里。)即使使用线程安全函数,您也不能在另一个线程正在或可能正在使用资源时释放资源。如果您担心性能,您可以使用
    fputs(str,fp)而不是
    fprintf(fp,“%s”,str)
    @AndrewHenle谢谢,性能差异是由于fprintf()中的格式处理开销造成的吗?@wei是由于fprintf()中的格式处理开销造成的性能差异吗?是的。根据实施情况,它可能是实质性的。例如,前1200行左右都是在
    fprintf()
    处理中使用的宏(GLIBC使用
    vfprintf()
    实现
    fprintf()
    )(请注意,在该实现中,仅传递一个简单字符串会绕过所有处理过程-不要使用该方法,因为如果有人将包含
    %
    的字符串传递给您的
    log()
    调用,则会导致问题。)啊,这个不确定值解释了我看到的崩溃。如果使用freopen()就像我在orig post中编辑的一样?@wei如果我像在orig post中编辑的一样使用freopen(),那会怎么样?这可能会更糟,具体取决于实现情况。我看不到任何保证要求
    freopen()
    始终保持内部一致的
    文件*
    对象。即使它是静音的,隐含的
    fclose()< /代码>可以在调用<代码> fPrtff()中的任何线程下使对象无效。
    。它可能会工作,但即使它工作了,这样做最好也取决于实现,最坏情况下是未定义的。@因为freopen首先关闭与流关联的文件,在打开它之前,行为仍然未定义。@AndrewHenle&2501谢谢,我想我必须在fprintf/fputs()之前使用rdwr锁@您应该能够使用
    flockfile()
    funlockfile()
    并包装整个
    日志()而不是单独的互斥锁或其他锁
    函数。有关说明和示例,请参阅和:注意,如果您在Linux或Solaris上运行,可以将流设置为绕过
    文件*
    对象的内部锁定,从而使整个
    日志()
    调用原子只有一个锁定/解锁周期。我得到的印象是,写入一个关闭的文件流会返回错误,但我没有意识到“f”可能指向无效的内容。如果我像我在orig post中编辑的那样使用freopen()会怎么样?如果
    freopen()
    由于某些原因返回一个错误。否则,我认为它可能没问题。但我真的不是100%确定。谢谢。我看了一下glibc的freopen()实现,它不会释放文件数据,因此它始终保持文件锁,不像fclose()那样释放锁然后释放文件结构。但我想这可能是实现依赖的,正如Andrew在另一个答案中所说。