0

我有一个程序,其中主进程分叉成 4 个相互合作的子进程:

process0 正在打开 FIFO 文件(O_WRONLY),使用 read 函数从 STDIN 一次读取 1 个字节,使用 write 写入 FIFO 并关闭 FIFO 文件

process1 正在等待共享内存为空(我正在使用共享内存表的第一个字节 if(tab[0] == 0) 检查它是否为空)打开 FIFO 文件(O_RDONLY),从中读取,翻译这个一个字节转换为十六进制并将其保存到共享内存中。然后它关闭 fifo 并将作为共享内存表的 tab[0] 设置为 1。

如果 tab[0] == 1,则 process2 正在从共享内存中读取。读取后将数据写入管道

process3 正在从管道读取并写入 STDIN

这一切都很完美。当我想添加信号时,问题就开始了。我正在使用信号量来同步 p0 和 p1,使用信号来同步 p1 和 p2,并使用消息队列来同步 p2 和 p3。它也可以正常工作,除了例如 process1 处于睡眠模式的时候。当它想从 fifo 读取并必须等待数据传输时,它会进入此模式。我猜。我一直在阅读它。

进程层次结构

以下是我发现的原因,我认为可能是原因:

“当进程在用户模式 ​​(1) 下进行系统调用时,它会进入状态 2,开始在内核模式下运行。假设此时进行的系统调用是读取硬盘上的文件。因为读取不是立即进行的,进程进入睡眠状态,等待系统已经读取磁盘并且数据准备好。现在处于状态4。当数据准备好时,进程被唤醒。这并不意味着它立即运行,而是它再次准备好在主内存中运行 (3)。”

我想我明白了,但我怎样才能避免这种情况呢?我希望我的程序始终对信号做出反应。当我通过“kill”发送信号时,是否有某种方法可以将进程状态从睡眠状态更改为运行状态?我可以以某种方式告诉进程停止“等待系统已读取磁盘并且数据准备就绪的事件”吗?

如果有人想看,这是我的代码:

程序代码

4

2 回答 2

1

如果我正确理解您的问题,则进程 1 将在第 442 行(源)挂断并且没有响应信号,因为它位于read.

显而易见的答案是不要做阻塞read()。检查描述符以查看是否有任何可读取的内容,如果没有则继续。阅读fcntl/ioctl以及如何进行非阻塞读取。

于 2012-09-17T14:22:45.443 回答
1

如果出现信号,您的观察结果可能是(大多数)系统调用默认重新启动。简而言之,这意味着在传递信号时卡在系统调用中的代码会唤醒到用户空间,但在信号处理程序运行后恢复系统调用。

如果使用sigaction () 而不是 signal() 函数来建立信号处理程序,则系统调用在捕获信号时不会重新启动,而是会失败并将 errno 设置为 EINTR。这意味着您必须处理这样一个事实,即系统调用可能由于传递的信号而在任何地方“失败”。

(signal()默认会在linux重启时引起系统调用,在包含signal.h头文件之前可以通过一些特性宏来控制。sigaction()是否引起系统调用重启由建立信号时的SA_RESTART标志控制处理程序)

于 2012-09-17T14:33:37.130 回答