C:如果文件描述符被删除,阻塞读取应该返回。

3

我正在从设备/文件描述符中以阻塞方式读取数据。可能会出现在另一个线程中关闭设备并删除文件描述符的情况。不幸的是,读操作不会返回或注意到这一点,而是继续阻塞。

作为一种解决方法,我可以使用select函数设置超时的while循环。如果发生超时,我可以检查文件描述符,如果已经不存在,则不进行读取操作,而是直接返回。

我想知道,在Linux-C中是否有更好的方法?


我可以检查文件描述符,检查什么,请问? - alk
“...并且文件描述符被删除”,一个文件描述符如何被“删除”? - alk
如果文件描述符已经被传递给close()并且在此期间没有被其他线程“回收”,则读取将失败并返回-1,这不一定等于EOF - alk
我的意思是:在执行close(fd)之后,我会将fd设置为null,这样我就能控制它是否仍然存在。 - Arno
1
执行 fd = NULL 不是一个好主意(NULL 是一个 指针 值!),因为这会把 fd(它是一个 int)赋值为 0,这几乎总是一个 有效的文件描述符。如果要标记文件描述符为无效,请使用任何 <0 的值。或者你应该使用由 fopen() 返回的 文件句柄/指针,类型为 FILE* - alk
2个回答

3
你所描述的代码存在固有的竞态条件——如果另一个线程在文件描述符上进行了阻塞式的read(),而你却调用了close()关闭了该文件描述符,那么另一个线程也可能正在准备调用read()
除非你知道所有其他线程都不再使用该文件描述符,否则你不能调用close()
处理像你描述的这种情况最简单的方法是让一个线程成为每个文件描述符的“拥有”线程,负责关闭文件描述符,而其他线程不直接关闭它——相反,它们将文件描述符标记为在某些共享数据结构中“要关闭”,并唤醒拥有线程。
你可以使拥有线程能够被唤醒,让它不是在read()中阻塞,而是在select()poll()中阻塞,其中包括另一个文件描述符(通常是管道)作为目标文件描述符和集合中的一部分。通过向该管道的另一端写入内容来唤醒线程。

我确实有类似的东西。一个主线程,打开设备,分配内存......,在同一时间调用关闭函数,一旦处理完成。但你是对的,与其在另一个线程中关闭和终止读取,我最好先终止读取,然后再关闭文件描述符。所有这些都可以像最初描述的那样工作(while循环,检查此变量,选择,读取)。我想这就是你的意思吧? - Arno
@user3392481:是的,尽管如果读取文件描述符的线程也是负责在看到标志设置后关闭它的线程,则会更容易(否则,您需要额外的同步来确保唤醒的线程已经唤醒并完成了文件描述符 - 就像由互斥锁和条件变量保护的引用计数)。 - caf

2

当一个文件描述符被其他线程关闭后,很难验证它是否已经发生了。如果其他线程重新打开一个文件并获得相同的文件描述符怎么办?在成功的close()调用上,你无法再次访问文件描述符,它将是未定义的。在失败的close()调用上,POSIX将文件描述符的状态未指定

select()选项也遇到了与上述相同的问题。

你的问题实际上与多线程程序中的任何其他数据竞争问题没有什么不同。我建议您重新编写代码,使线程在没有同步的情况下不访问文件描述符。或者,如果可能的话,避免多个线程从同一文件描述符读取。


1
哦,这是分开的。在应用程序的最后,你要确保关闭所有的线程,并且这个读取操作不会放弃。 - Arno

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接