首页 > 解决方案 > 关于阻塞系统调用和潜在的竞争条件

问题描述

我们对网络套接字使用阻塞系统 I/O 调用。我们想要的行为是当close()在socket上调用时,阻塞调用需要返回并抛出异常(reference),

查看 OpenJDK,这就是它的实现方式。它使用用户信号来唤醒阻塞线程。相应的信号处理程序是No-OP。在阻塞调用之前,它会注册可能被阻塞的线程。当文件描述符关闭时,关闭线程会向阻塞的 I/O 线程发送一个信号,这会导致阻塞调用返回EINTR

但是,我仍然认为以下代码块中存在潜在的竞争条件:

  startOp(fdEntry, &self);  // (1)
  ret = FUNC;               // (2)
  endOp(fdEntry, &self); 

在I/O线程中,(1)执行,然后关闭线程调用close并发送信号给(2)开始执行之前的I/O线程。信号被接收并丢弃。当 (2) 开始在 I/O 线程中执行时,它会进行阻塞系统调用。在这个阶段,fdEntry 可能已关闭,或者即将关闭。

我理解正确吗?我是否做出了错误的观察,或者竞争条件的可能性很低,所以我们可以放心地忽略它?

标签: javamultithreadingunix

解决方案


回答自己:事实证明这确实是一个错误。修复就在close一边:我们首先关闭文件描述符,然后向阻塞线程发出信号。如果阻塞线程错过信号并启动阻塞调用,它将立即返回,EBADF因为文件描述符已关闭。


推荐阅读