wei
wei

Reputation: 6889

Are fclose(), fprintf(), ftell() thread_safe only in terms of each function itself?

Glibc says fclose()/fopen()/fprintf()/ftell() are thread-safe. But what happens when one thread is writing to or reading the file and another thread is closing the file?

Say I have a function looks like this

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);
   }
} 

This function is used by multiple threads to write to file. Is it safe,i.e. no crashes? Note that function returning error is fine, my experiments show that the program crashes intermittently.

EDIT: 1. as @2501 pointed out, "The value of a pointer to a FILE object is indeterminate after the associated file is closed", this explains the intermittently crashes. What if I rewrite the code using 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);

Upvotes: 4

Views: 1189

Answers (2)

Michael Burr
Michael Burr

Reputation: 340188

Each of those functions locks a mutex associated with the FILE*. So those functions are 'atomic' with respect to the particular FILE* object. But once the FILE* object is closed, it's invalid for use. So if the FILE* gets closed and a another thread tries to use that closed FILE*, then you'll have a failure due to trying to write to a closed file.

Note that this is aside from any data race you might have with the f variable being changed without synchronizing with other threads. (from the code snippet we see, it's not clear whether there's a race there, but I'm guessing that there probably is).

Upvotes: 3

2501
2501

Reputation: 25752

After the stream is closed using fclose, the value of the FILE pointer is indeterminate. This means that using it causes undefined behavior.

7.21.3 Files

  1. ... The value of a pointer to a FILE object is indeterminate after the associated file is closed ...

Since the fprintf call may happen by other threads in the time between the fclose() and open(), when the value of the pointer f is indeterminate, the behavior or your code is undefined.

To make the code defined, the fprintf call, and any other call using the pointer, should be locked by the mutex as well.

Upvotes: 2

Related Questions