c - 基于c中的计时器写入管道,阻塞问题

标签 c timer pipe blocking

我正在使用 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/

相关文章:

c - 提取 int 二进制表示的最后四位数字

c - 这个AVL平衡代码有什么问题?

从服务更新 android 小部件 - 内存泄漏?

linux - 为什么我的 Linux 管道卡住了?

c - 为什么 malloc 和 sbrk 从不同的段返回地址?

javascript - 如何在点击时启动计时器?

Java Swing 计时器不工作

c - 如何在 execvp 之后在子进程中使用文件描述符?

c - 通过管道将图像发送到C中的子进程

c - 如何打印带父节点的层序二叉搜索树