我有以下情况:
有一个线程从具有fread调用的设备读取。只要没有数据从设备发送,此呼叫就会被阻止。 当我停止这个线程时,它仍然挂在这个线程内。
现在我在fread的手册页中找到了以下内容:
错误
在所有符合的系统上 单一UNIX规范,fread() 函数设置errno列出的 以下条件:
[EINTR]读取操作是 因收到a而终止 信号,没有传输数据。
这意味着有一种方法可以从不同的线程中断调用。但我不知道怎么做。有人能告诉我如何发送信号来中断这个电话吗?我需要发出什么信号?
更新08-10-10 09:25
我仍然没有工作。我用不同的信号尝试了kill()和pthread_kill()。但似乎没有什么能打断fread()调用。我唯一能做的就是杀死整个应用程序,但这不是我想要的。
答案 0 :(得分:9)
<强> 1。信号:强>
许多其他人指出,使用信号会起作用。然而,正如许多其他人也指出的那样,这种方法有其缺点。
<强> 2。选择():强>
使用select()(或其他多路复用功能),可以阻止等待数据从多个文件描述符到达,并指定超时。
使用超时功能。每当select()返回时,检查一个全局变量以查看是否必须终止。如果你想立即反应,继续阅读。
第3。选择()和管道:
多个fds意味着您可以等待通过您提到的设备到达的数据,例如管道。
在创建线程之前,创建一个管道,然后让select()上的线程块监视设备和管道。无论何时要取消阻止选择设备是否有新数据,都要向管道发送一个字节。
如果select()告诉您由于数据通过管道到达而解锁,您可以清理并终止。请注意,此方法比信令方法更灵活,因为除了使用管道作为唤醒方法之外,您还可以使用它来传递有用的信息或命令。
<强> 4。选择(),管道和信号:
如果您正在使用多个进程并且不希望/无法传递管道,则可以将两个解决方案结合使用。创建一个管道并为SIGUSR1安装一个信号处理程序。在信号处理程序中,向管道发送一个字节。
每当进程发送SIGUSR1时,将调用该处理程序并取消阻塞select()。通过检查fdsets,您将知道除了您自己的程序发出信号之外没有其他原因。
答案 1 :(得分:4)
您真的想要阅读有关select(2)
系统调用的信息,这将允许您查看该文件描述符上是否有可用数据,完全没有阻塞或仅仅阻止该设备。
答案 2 :(得分:3)
看看man 2 kill
。 (或参见here)
我觉得你不想这样做 - 大多数时候人们忽略了错误EINTR
并再次阅读。您可能希望查看非阻塞读取。
答案 3 :(得分:2)
在主题中,不是使用fread
进行屏蔽,而是使用select
进行屏蔽。当select
返回时,请检查“我是否已完成”变量。如果没有完成,您可以致电fread
获取数据。
从另一个线程 - 想要停止fread线程 - 你可以设置“我完成”变量然后关闭fd,以便fread线程立即从select
唤醒。 / p>
如果你的上下文禁止你关闭fd(你提到你正在读取设备,但是说你有一个你希望保持打开的套接字),你可以打开第二个fd,你从另一个线程写到醒来select
。
正如下面的评论中所建议的那样,关闭fd以唤醒select
可能无法移植。您可以使用上面提到的第二种策略来实现更便携。
答案 4 :(得分:0)
答案 5 :(得分:0)
信号处理程序不会中断fread
,除非它们被安装为中断,未处理的信号永远不会中断。 POSIX标准允许signal
函数安装的处理程序默认中断或不中断(在Linux上默认为不中断),因此如果您需要特定行为,请使用{{1} }功能并指定所需的sigaction
。特别是,您需要省略sa_flags
标志。例如:
SA_RESTART
请注意,如果省略struct sigaction sa = { .sa_handler = dummy_func, .sa_flags = 0 };
sigaction(SIGUSR1, &sa, 0);
,则隐式为0,但我在初始化程序中明确地将其包括在内以进行说明。然后,您可以通过sa_flags
或fread
发送SIGUSR1
来中断kill
。