6

I have the following situation:

There is a thread that reads from a device with a fread call. This call is blocking as long as there is no data send from the device. When I stop this thread it remains hanging inside this thread.

Now I found the following inside the man page of fread:

ERRORS

On all systems that conform to the Single UNIX Specification, the fread() function sets errno as listed for the following conditions:

[EINTR] The read operation was terminated due to the receipt of a signal, and no data was transferred.

That would mean there is a way to interrupt the call from a different thread. But I have no idea how. Can someone tell me how to send a signal to interrupt the fread call? And what signal I need to send?


Update 08-10-10 09:25

I still haven't got it to work. I tryed the kill() and pthread_kill() with different signals. But nothing seems to interrupt the fread() call. The only thing that I got working is killing the entire application, but that's not what I want.

4

6 回答 6

10

1. 信号:

正如许多其他人指出的那样,使用信号会起作用。然而,正如许多其他人也指出的那样,这种方法有其缺点。

2.选择():

使用 select()(或其他多路复用函数),您可以阻止等待来自多个文件描述符的数据到达,并指定超时。

使用超时对您有利。每当 select() 返回时,检查一个全局变量以查看是否必须终止。如果您想立即做出反应,请继续阅读。

3. Select() 和管道:

多个 fds 意味着您可以等待数据通过您提到的设备到达,例如管道。

在创建线程之前,先创建一个管道,然后让 select() 上的线程块同时监控设备和管道。每当您想取消阻止选择设备是否有新数据时,请沿管道发送一个字节。

如果 select() 告诉您由于数据通过管道到达而解除阻塞,您可以清理并终止。请注意,此方法比信号方法灵活得多,因为除了将管道用作唤醒方法之外,您还可以使用它来传递有用的信息或命令。

4. Select()、管道和信号:

如果您正在使用多个进程并且不想/不能绕过管道,则可以结合使用这两种解决方案。创建一个管道并为 SIGUSR1 安装一个信号处理程序。在信号处理程序中,沿管道发送一个字节。

每当进程发送 SIGUSR1 时,将调用处理程序并取消阻塞 select()。通过检查 fdset,您将知道这只是您自己的程序发出信号本身的原因。

于 2010-10-07T20:25:12.667 回答
4

您真的很想了解select(2)系统调用,这将允许您找出该文件描述符上是否有可用数据,完全没有阻塞或仅在该设备上没有阻塞。

于 2010-10-07T14:07:14.723 回答
3

看看man 2 kill。(或看这里

不过,我感觉您不想这样做——大多数时候人们会忽略 errnoEINTR并再次阅读。您可能想研究非阻塞读取。

于 2010-10-07T14:03:24.797 回答
2

在线程中,不是用 阻塞,而是用fread阻塞select。返回时select,检查“我完成了吗”变量。如果没有完成,您可以致电fread获取数据。

从另一个线程——想要停止 fread 线程——你可以设置“我完成了吗”变量,然后关闭 fd,以便 fread 线程select立即唤醒。

如果您的上下文禁止您关闭 fd(您提到您正在从设备读取,但说您有一个想要保持打开的套接字),您可以打开第二个 fd,您可以从另一个线程写入来唤醒select

正如下面评论中所建议的那样,关闭 fd 以唤醒select可能是不可移植的。您可以使用上面提到的 second-fd 策略来实现这一点更便携。

于 2010-10-07T15:53:36.903 回答
0

您可以使用kill()系统调用。

更新

原来我误读了你的问题。正如 R. 在下面指出的那样,kill()仅用于杀死进程,而不是线程。

于 2010-10-07T14:04:34.163 回答
0

信号处理程序不会中断fread,除非它们被安装为中断,并且未处理的信号永远不会中断。POSIX 标准允许signal函数安装的处理程序默认为中断或非中断(在 Linux 上默认为非中断),因此如果您需要特定行为,请使用该sigaction函数并指定所需的sa_flags. 特别是,您需要省略SA_RESTART标志。例如:

struct sigaction sa = { .sa_handler = dummy_func, .sa_flags = 0 };
sigaction(SIGUSR1, &sa, 0);

请注意,sa_flags如果省略,无论如何都会隐含为 0,但我将它明确包含在初始化程序中以进行说明。fread然后您可以通过发送SIGUSR1来中断killpthread_kill

于 2011-06-04T16:35:22.160 回答