3

I am reading in a blocked way from a device/filedescriptor. It might happen, that in a different thread the device is closed and filedescriptor is deleted. Unfortunatly the read doesn't return or take notice and keeps blocking.

As a workaround I could do a while loop with select as a timeout. If a timeout happens, I can check the filedescriptor and in case it is gone not calling read but return.

I am wondering, if there is a better way in Linux-C ?

Arno
  • 257
  • 1
  • 10
  • "*I can check the filedescriptor*" check what, please? – alk Oct 28 '16 at 09:15
  • "*... and filedescriptor is deleted*" how can a file descriptor be "*deleted*"? – alk Oct 28 '16 at 09:16
  • @MarekKlein: If the file descriptor had been passed to `close()` already and had not been "recycled" in the mean time yb another thread, reading will fail and return -1, which not necessarily needs to be equal to `EOF`. – alk Oct 28 '16 at 09:27
  • what I mean: After close(fd); I do a fd=Null; so that I have some kind of control whether it is still existing – Arno Oct 31 '16 at 06:22
  • 1
    Doing `fd = NULL` is not a good idea (`NULL` is a ***pointer*** value!), as this would assign to `fd` (which is an `int`) mostly likely the value of `0`, which ***is*** a valid file descriptor. To mark a file descriptors as non-valid use any value `<0`. Or should you be using ***file handles/pointers***, typed `FILE*`, as returned by `fopen()`. – alk Oct 31 '16 at 10:09

2 Answers2

3

The code you are describing has an inherent race condition - if another thread could be a in blocking read() on a file descriptor when you close() that file descriptor, the other thread could just as well be just about to call read() instead.

You can't call close() unless you know that all other threads are no longer in a position to be using that file descriptor at all.

The easiest way to handle cases like you describe is for one thread to be the 'owning' thread of each file descriptor, that is responsible for closing the file descriptor. Other threads don't directly close it - instead they mark the file descriptor as "to be closed" in some shared data structure and wake up the owning thread.

You can make it possible to wake the owning thread by having it not block in read() but instead block in select() or poll() with another file descriptor - usually a pipe - in the set as well as the target file descriptor. The thread is woken by writing to the other end of that pipe.

caf
  • 233,326
  • 40
  • 323
  • 462
  • I do have something like that. One main thread, opening devices, allocating memory ..., and in the same the close function is called, once the processing is done. But you are right, instead of closing and terminate the read in another thread I better should do first terminating reading and than close filedescriptor. All that could work simular as described initially (while loop, check for this variable, select, read). I think this is what you mean? – Arno Oct 31 '16 at 06:37
  • @user3392481: Yes although it is much easier if the thread that is reading the file descriptor is also the one responsible for closing it once it has seen the flag is set (otherwise, you need additional synchronisation to ensure that the woken thread has woken and finished with the file descriptor - like a reference count protected by mutex and condition variable). – caf Oct 31 '16 at 23:11
2

Once a file descriptor is closed by other thread, it's not easy to verify it happened. What if other thread re-opened a file and got the same file descriptor? On a successful close() call, you can't access the file descriptor again and it'll be undefined. On a failed close() call, POSIX leaves the state of the file descriptor unspecified.

The select() option suffers from the same as described above.

Your problem is not really anything different to any other data race issue in a multi-threaded program. I suggest you re-write the code so that threads don't access the file descriptor without synchronization. Or, avoid multiple threads reading from the same file descriptor if that's possible.

P.P
  • 117,907
  • 20
  • 175
  • 238
  • 1
    Oh, this is separated. It is just at the end of the applictaion you wanna be sure to close all threads and this read will not give up. – Arno Oct 31 '16 at 06:45