我正在使用 C 将数字写入命名管道。我想每 1 秒写入一次,因此我使用与此类似的代码来设置计时器:
need programs that illustrate use of settimer and alarm functions in GNU C
在上面的计时器每 1 秒调用一次的 DoStuff() 例程中,我使用 mkfifo() 打开一个命名管道并使用 write() 写入它。
然后我用一个单独的程序读取来调用它。
现在,问题是,例如,另一个程序只能每 3 秒调用一次“read”。然而。我仍然希望“写入”每 1 秒发生一次。
基本上,我希望第一个程序执行此操作:
- 设置 1 秒间隔的计时器。
- 每 1 秒向管道写入一个数字。
- 将数字加倍(最多达到某个最大值)。
然后是执行此操作的第二个程序:
- 每 3 秒(或每当该值可变时)从管道中读取一次。
- 读取最近写入管道的数字。
也就是说,如果两个程序都启动,则可能会发生以下情况:
- 第二个 1:第一个程序将“1”写入管道。
- 第二个 2:第一个程序将“2”写入管道。
- 第二个 3:第二个程序从管道读取“2”,并且第一个程序将“4”写入管道。
- 第二个 4:第一个程序将“8”写入管道。
- 第二个 5:第一个程序将“16”写入管道。
- 第二个 6:第二个程序从管道读取“16”,并且第一个程序将“32”写入管道。
但最终发生的是这样的:
- 第二个 1:第一个程序将“1”写入管道。
- 第二个 2:什么都没有
- 第二个 3:第二个程序从管道读取“1”,并且第一个程序向管道写入“2”。
- 第二个 4:什么都没有
- 第二个 5:什么都没有
- 第二个 6:第二个程序从管道读取“2”,并且第一个程序将“4”写入管道。
我发现管道写入在被读取之前是阻塞的,所以它似乎阻止了第一个程序中的计时器继续运行,直到第二个程序读取它。处理使其非阻塞的最佳方法是什么,或者还有其他解决方案吗?抱歉,我对管道和 fork 非常陌生,虽然我认为我了解总体方向,但我对具体细节很模糊,并且非常感谢任何资深人士的建议。
谢谢大家。
<小时/>编辑:根据下面第一响应者的说法,我使用的方法可能根本不是正确的方法,因此我将概括地描述该问题以寻求进一步的建议。
程序 1 需要每 1 秒更新一个变量,同时它还同时执行其他操作。
程序 2 需要能够访问该变量的最新值。
我最初的想法是在程序 1 中设置一个计时器,每 1 秒更新一次变量,然后让程序 2 通过管道读取变量。我试图使用 setitimer() 和 signal() 进行更新,但是每次我写入管道时,它都会被阻塞直到读取,这意味着如果读取速度不够快,每秒更新可能不会发生.
关于如何最简单地解决这个问题的一般建议?我对 fork 进程和线程缺乏经验。谢谢。
我正在考虑最简单的解决方案可能是使用我已经在使用的计时器,但只需将其值写入实际文件,然后其他程序就可以读取该文件。这样就没有管道,所以不会阻塞。这看起来合理吗?
或者,如果在第二个程序中,我有第二个计时器循环每 1 秒从管道读取一次怎么办?
最佳答案
请不要这样做。你的头最终会受伤。首先,要在信号处理程序中执行任何操作,您需要确保所做的每个调用都是异步安全的(有时称为信号安全)。异步安全函数列表位于 signal(7)
的联机帮助页中,即 here .
更好的主意是使用带有超时的 select
循环,并使用 gettimeofday
或类似方法检查时间。
如果您必须使用SIGALRM
,请将信号处理程序保持在最小长度,并简单地写入“自管道”。您在这里要做的是设置一个专用管道(在信号处理程序之外),向信号处理程序中的管道写入一个字符,然后在主程序的管道的读取端上使用 select()
select()
循环。详细信息在这里:Using self-pipe, how can I avoid that the event loop stalls on read()? - 关于其起源的有用背景here .
但在我看来,这就像 select()
循环的经典案例,并且没有计时器。
信号(或者更确切地说在其中执行任何复杂的操作)是出了名的难以调试,容易出现竞争条件,遭受重入问题,不可移植,因此是不可预测的。
如果您坚持使用 SIGALRM
,除非您发布一个最小的错误示例,否则我们将无法调试您的程序。
关于c - 基于c中的计时器写入管道,阻塞问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26663191/