【问题标题】:Linux, cancel blocking read()Linux,取消阻塞 read()
【发布时间】:2013-05-19 16:53:40
【问题描述】:

在用于串行通信的多线程 Linux 程序中,是否可以(以及最好的方法)终止来自另一个线程的阻塞 read() 调用?

我希望尽可能保持反应性,并避免在重复轮询时使用任何超时。

这个问题的背景是我正在尝试使用 JNI 为 Linux 创建一个 Scala 串行通信库。我试图使本机端尽可能简单,提供 read() 和 close() 函数等。在 Scala 方面,一个线程会调用 read() 并阻塞,直到来自串行端口的数据可用。但是,可以通过其他方式关闭串口,从而调用 close()。现在,为了释放被阻塞的线程,我需要取消系统读取调用。

【问题讨论】:

标签: linux multithreading io java-native-interface blocking


【解决方案1】:

一个相当流行的技巧:不是在 read() 中阻塞,而是在你的串行套接字和管道上阻塞 select()。然后,当另一个线程想要唤醒您的线程时,它可以通过向该管道的另一端写入一个字节来实现。该字节将导致 select() 返回,您的线程现在可以清理并退出或任何它需要做的事情。 (请注意,为了使这项工作 100% 可靠,您可能希望将串行套接字设置为非阻塞,以确保您的线程仅在 select() 中阻塞,而从不在 read() 中阻塞)

【讨论】:

  • 附议。我几乎所有的多线程编程都是这样。这是通信顺序过程(CSP)中的一种模式。鉴于 Scala 确实通信 Scala 对象(CSP 的实际实现),我认为您的建议非常合适。顺便说一句,为 Windows Win32 或 .NET 编程的最大缺点是您不能在管道上选择(),这是一个巨大的遗漏。 MS 会让你相信异步 IO 更好,但它会导致代码非常混乱。 Cygwin 项目在编写 select() 时遇到问题。他们的解决方案涉及大量线程和轮询。
  • FWIW 您可以在 Windows 下通过创建两个 TCP 套接字并将其中一个连接到另一个套接字来执行相同的技巧(只需 10 倍;),如下所示:@987654321 @
  • 感谢您的回答! Select 对我不起作用(也许我做错了什么),但是在阅读 select() 手册页时,我偶然发现了 poll()。效果很好:)
  • 使用管道也被证明对于向线程发送数据很有用。为了表示是时候关闭线程了,我只是简单地close'd 来自主线程的管道。当阻塞线程在管道上获得POLLHUP时,它可以关闭。
  • @PiCTo 我认为您需要修改等待线程以将POLLIN 添加到其poll() 调用中,以便当一个字节到达其通知管道时它也会返回。跨度>
【解决方案2】:

AFAIK 信号是使任何线程脱离阻塞系统调用的唯一方法。

使用pthread_kill() 指向带有 USR1 信号的线程。

【讨论】:

  • 感谢您的回答,但 pthread_kill 在我的用例中是不可能的(因为函数是从 JVM 的不同线程调用的)。我可以使用任何解决方法吗?我听说过一些关于 epoll 的东西,但我的测试也没有成功。
  • 我对 JNI 了解不够,无法提出建议。您可能会在一个线程中使用epoll,而在另一个线程中使用close(),但我认为这是未定义的行为。
【解决方案3】:

你可能会做假数据输入:

tty_ioctl(fd,TIOCSTI,"please unblock!");

在调用它之前,您应该设置一些全局标志,以便能够在 'read(...)' 返回后检查接收到的数据是否只是唤醒 goo 或更重要的东西。

来源:https://www.systutorials.com/docs/linux/man/4-tty_ioctl/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-17
    • 2013-10-23
    • 1970-01-01
    • 2014-06-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多