I just debugged a program that did roughly:
pthread_create(...);
close(0);
int t = open("/named_pipe");
assert(t == 0);
Occasionally it fails, as pthread_create
actually briefly opens file descriptors on the new thread – specifically /sys/devices/system/cpu/online
– which if you're unlucky occur between the close
and open
above, making t
something other than 0.
What's the safest way to do this? What if anything is guaranteed about pthread_create
regarding file descriptors? Am I guaranteed that if there are 3 file descriptors open before I call pthread_create, then there'll also be 3 open when it's returned and control has been passed to my function on the new thread?
In multi-threaded programs, you need to use dup2
or dup3
to replace file descriptors. The old trick with immediate reuse after close
no longer works because other threads and create file descriptors at any time. Such file descriptors can even be created (and closed) implicitly by glibc because many kernel interfaces use file descriptors.
dup2
is the standard interface. Linux also has dup3
, with which you can atomically create the file descriptor with the O_CLOEXEC
flag set. Otherwise, there would still be a race condition, and the descriptor could leak to a subprocess if the process ever forks and executes a new program.