pipe() 和 socket() 线程安全吗? (双重关闭()问题)

Are pipe() and socket() thread safe? (double close() problem)

我正在使用 g++ (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0
uname -a Linux ubuntu 4.18.0-17-generic #18~18.04.1-Ubuntu SMP Fri Mar 15 15:27:12 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

我认为所有创建文件描述符的系统调用在 Linux 上都是线程安全的。 我的意思是,从不同线程并行调用 socket()pipe() 不应该 return 相同 fd。 是不是真的?

在您的示例程序中,除了 pIsI 之外,每个全局变量都有 data races。您从一个线程读取它们,同时从另一个线程写入它们。这会导致未定义的行为,这意味着您从该程序获得的任何结果都是无意义的。

两个 socket and the pipe 函数都是 thread-safe,并且可以安全地从异步信号处理程序中使用。奇怪的是,手册页不包含这些信息,但联机文档包含。

这不太公平,因为我没有真正展示任何真实代码,但为了其他用户,我想回答我自己的问题。

  • 我看到的症状是像这样的错误
    • errno 9 (Bad file descriptor)
    • 应用程序死锁(由于在错误的文件描述符上与其他进程通信)
  • 这是一个多线程环境。
  • 由于我为了调试而添加的日志,我开始怀疑 socket()pipe() 不是多线程安全的。我看到两个不同的线程同时使用同一个 fd(我没有把日志放在所有相关的地方,这就是为什么我看到这个奇怪的事件)。
  • 多亏了这个 Double close() 段落,我明白这是我的问题的变体:
    • 线程 1 open() fd 100
    • 线程 1 close() fd 100关闭 #1 <--- 这是错误
    • 线程 2 open() fd 100(现在完全没问题,进程中的任何线程都没有使用 100
    • 线程 1 close() 再次 fd 100关闭#2。
      • 这秒close()实际上关闭了线程2的fd100,那么当线程2使用这个fd时,它会得到errno 9 (Bad file descriptor)使用关闭的fd。
      • 它也可能变得更复杂:此时 fd 100 被关闭。它可能被另一个与 read()/write() 一起使用的线程 re-opened。线程 2 也会将它与 read()/write() 一起使用 - 这种情况下,两个线程使用相同的 fd 是错误的,并且会使该 fd 上的数据 sent/received 无效。