如果文件描述符关闭,Linux write() 会使应用程序崩溃

Posted

技术标签:

【中文标题】如果文件描述符关闭,Linux write() 会使应用程序崩溃【英文标题】:Linux write() crashes application if file descriptor is closed 【发布时间】:2020-10-27 14:05:03 【问题描述】:

在我的 C++ 应用程序中,一个线程使用 poll() 函数在文件描述符打开、数据可供读取和 fd 关闭时得到通知。当数据可用时,它被读取并交付给其他线程进行处理和回复。事实上,另一方面,客户端在打开的套接字上等待同步回复。 当一个 fd 不再可用时,我尽最大努力通知其他线程,但不同步(目前)跨所有线程设置的文件描述符。 问题是这段代码:

while(bytes < len && d->ok) 
        w = write(fd, buf + bytes, len - bytes);
        d->ok = (w >= 0);
        if(d->ok)
            bytes += w;
    
    

fd 关闭后整个应用程序崩溃。

预期行为:写入返回负数但没有崩溃。 我已经阅读了发送 SIGPIPE 的一些线程,这就是应用程序崩溃的原因,但我发现它没有明确记录在

人写

我想到的选项:

同步文件描述符集,这样一旦 poll() 通知 fd 关闭,其他线程就不再使用它了 使用 send() 而不是 write。

但是,我想,如果 fd 在我处于 write() while 循环时被另一端关闭,我会得到一个崩溃而不是 write() 的简单否定结果

我做错了什么? 感谢您的任何建议

【问题讨论】:

【参考方案1】:

I/O函数可能会导致SIGPIPE,数据写入越快,可能性越大。不幸的结果是您的应用程序只是崩溃而您没有机会处理错误,这确实可能非常令人困惑。要解决这个问题,您只需将 SIGPIPE 的信号处理程序设置为 SIG_IGN - 然后 write() 将改为返回 -1 并带有 errno=EPIPE(断管),您可以关闭侧面描述符并正确清理。

【讨论】:

【参考方案2】:

如果文件描述符可以在一个线程中关闭,而另一个线程正在或可能正在使用它,那么您将永远无法让您的代码可靠地工作。您必须使用某种形式的同步。

作为可能出错的一个示例,请考虑以下情况:

    线程 A 关闭文件描述符 10,就像线程 B 即将write 一样。 在线程 B 可以写入之前,线程 C 打开并连接一个新的套接字,它恰好发生在描述符 10 中。 线程 B 终于开始执行,写入文件描述符 10,但现在这是线程 B 打开的新连接。

糟糕,您只是将信息写入了错误的端点。我希望它不是安全敏感的。

您必须确保一个线程不可能释放资源,而另一个线程正在或可能正在使用它,因为如果您不这样做,您将总是有一个可能的竞争条件,其中一个线程释放资源正确 另一个线程尝试访问它之前。这可能是灾难性的。

【讨论】:

以上是关于如果文件描述符关闭,Linux write() 会使应用程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章

Linux下的基础IO

C 读取和线程安全 (linux)

C++笔记--Linux编程-linux文件和输入输出 文件和目录操作

如何重新打开已关闭的文件描述符

linux中文件I/O操作(系统I/O)

linux中read,write和recv,send的区别