4

What will happen if fwrite & fclose are called in parallel from two threads for the same file descriptor?

doron
  • 27,972
  • 12
  • 65
  • 103
Jay
  • 24,173
  • 25
  • 93
  • 141

3 Answers3

9

POSIX requires FILE access to be thread-safe, but since fclose closes the file and invalidates the pointer, there is no way (i.e. it's not just a specification issue but a fundamental API issue that could never be "fixed" or made to go away) to use fclose when another thread might be accessing the FILE still. You'll need to do your own locking.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
4

fwrite and fclose operate on the FILE data structure. Since this is a largish data structure that does store more than just the file descriptor, the answer is bad things.

Don't do this unless you ensure atomic operation using mutexes.

doron
  • 27,972
  • 12
  • 65
  • 103
  • This is incorrect, sort of. FILEs contain a mutex for thread-safety, assuming you have a correct POSIX implementation. Either your fwrite will go through entirely (or stop for reasons unrelated to thread safety, like a full disk), or it will have been fclosed() and you will get undefined behavior. But it can't fclose in the middle of a write. –  Sep 10 '10 at 16:29
  • 6
    -1 for explaining with guesswork and ending up with the wrong reasons why the OP can't use `fwrite` and `fclose` simultaneously. POSIX requires thread-safe `FILE` operations; the problem is that, if another thread may have called `fclose`, then you're potentially passing an invalid pointer to `fwrite` which results in undefined behavior. – R.. GitHub STOP HELPING ICE Sep 10 '10 at 16:31
  • @Joe, since there's no way to determine if you're "in the middle of a write", and since any program which can call `fclose` while `fwrite` is in progress could have instead called `fwrite` just after `fclose` finished (purely timing differences), I see no reason for an implementation to include any locking at all in `fclose`. The program already has undefined behavior and you might as well just let it crash and burn. – R.. GitHub STOP HELPING ICE Sep 10 '10 at 16:34
  • I have been looking at the source code for fwrite to understand the locking. Interestingly enough there is no locking of fwrite in Android and although the eglibc (used by Ubuntu) implementation has some sort of lock. I am still trying to see exactly how it works. – doron Sep 11 '10 at 13:11
  • 1
    @R.: I am not sure that is correct. Imagine a system of three threads; one writes "endfoobar" to FILE *x. Another is reading it three characters at a time; upon reading "end" it signals the third thread, which calls fclose(x), and stops reading. fclose may trigger the fwrite to end in a defined way early (e.g. EPIPE), but it must still synchronize with it to do that. I'm describing a fairly pathological program, but I believe it means fclose needs some level of synchronization. –  Sep 11 '10 at 17:52
  • @Joe: I don't entirely get your example since with a pipe, the reading and writing `FILE`s would be different. In any case, locks in objects that may be deallocated as soon as the lock is removed are nearly impossible to implement correctly without race conditions, as you can see from one of my questions about barrier implementations. I would need to see a very good argument to be convinced that stdio should try to handle locking with `fclose` (i.e. that there's any valid way to use `fclose` on a `FILE` while other threads might not be finished accessing it). – R.. GitHub STOP HELPING ICE Jul 24 '11 at 13:44
  • My example doesn't require the reading and writing FILE*s to be the same. Both the writing and closing threads have access to the "write" end of the pipe, represented by the same FILE*. However the reading thread acts to synchronize them so that it is _certain_ fwrite will be started before fclose, and (in the absence of buffering) it is _certain_ that fclose will act before the f –  Jul 24 '11 at 14:35
-4

For such a circumstance you need to define priorities of your methods. You can control the methods with "synchronized".

telvin
  • 1