检测程序何时打开 fifo

2024-02-07

我遇到一种情况,我需要检查 fifo 的另一侧是否已打开它,但是我不能使用 open,因为否则程序将开始执行操作。

为什么我必须这样做:我有一个程序(监视器)来启动服务器程序(都是我创建的)。监视器使用此 fifo 进行通信,因为监视器可以在服务器已启动时关闭/重新打开。

问题是当监视器启动服务器时:在这种情况下,我必须以某种方式等待 fifo 创建,然后打开它们。 实际上,我在监视器上使用了一段时间来检查 fifo 何时创建,但是以这种方式它会打开 fifobefore服务器可以做到这一点(即使 mkfifo 之后的指令实际上是打开的!!!)。

你可能会说我在显示器上以错误的顺序打开fifo(我在读fifo之前打开写fifo(错误)),问题是我无法恢复这个顺序,因为它要求服务器将等待开放 (RDONLY) fifo 上的客户端。

关于如何避免这种竞争条件有什么建议吗? 实际上,在检查 fifo 是否创建后,我在监视器中使用睡眠,这显然解决了问题,但我认为绝对不正确。

谢谢大家

Edit 1:

这就是目前的情况

Server

mkfifo(fifo1)
mkfifo(fifo2)
open(fifo1 O_RDONLY)
open(fifo2 O_WRONLY)

Monitor

while (fifo1 doesn't exists && fifo2 doesn't exists);
open(fifo1 O_WRONLY)
open(fifo2 O_RDONLY)

我认为竞争条件现在非常明确,重要的是要注意 fifo 正在阻塞(只有 RDONLY 正在阻塞,WRONLY 不会阻塞,即使另一边没有任何人 =>这是 UNIX 行为,不是我设计的).

Edit 2:

竞争条件发生在第一个 fifo 打开级别。我必须在监视器执行此操作之前打开服务器上的第一个 fifo。


如果您以正确的顺序执行 open(),则不会出现竞争条件。 (唯一可能的竞争是第三个进程干扰相同的 fifo)来自精美手册:

“但是,必须同时在两端打开它,然后才能继续对其进行任何输入或输出操作。打开 FIFO 进行读取通常会阻塞,直到其他进程打开相同的 FIFO 写作,反之亦然。”

这意味着订购

{ 进程1:open(fifo1,RO); process2:打开(fifo1,WO); }

...

{ 进程1:打开(fifo2, WO); process2:打开(fifo2,RO); }

总是会成功(假设没有进程饥饿) 每个 fifo 上的操作顺序并不重要;对于 fifo1,进程 1 或进程 2 可以先行(并且将被阻塞,直到另一方成功)。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

#define FIFO1 "fifo1"
#define FIFO2 "fifo2"

void do_master(void);
void do_slave(void);
void randsleep(unsigned max);

/************************************/
void do_master(void)
{
int in,out, rc;
char buff[20];

randsleep(5);
mkfifo(FIFO1, 0644);
randsleep(7);
mkfifo(FIFO2, 0644);

out = open(FIFO2, O_WRONLY);
if (out == -1) {
    fprintf(stderr, "[Master]: failed opening output\n" );
    return;
    }
fprintf(stderr, "[Master]: opened output\n" );
in = open(FIFO1, O_RDONLY);
if (in == -1)  {
    fprintf(stderr, "[Master]: failed opening input\n" );
    close(out);
    return;
    }
fprintf(stderr, "[Master]: opened input\n" );

rc = write( out, "M2S\n\0" , 5);
fprintf(stderr, "[Master]: wrote %d\n", rc );

rc = read( in, buff , sizeof buff);
fprintf(stderr, "[Master]: read %d: %s\n", rc, buff );
unlink(FIFO1);
unlink(FIFO2);
}
/***********************************/
void do_slave(void)
{
int in,out, rc;
unsigned iter=0;
char buff[20];

loop1:
in = open(FIFO2, O_RDONLY);
if (in == -1) {
    fprintf(stderr, "[Slave%u]: failed opening input\n", ++iter );
    randsleep(2);
    goto loop1;
    }
fprintf(stderr, "[Slave]: opened input\n" );

loop2:
out = open(FIFO1, O_WRONLY);
if (out == -1) {
    fprintf(stderr, "[Slave%u]: failed opening output\n", ++iter );
    randsleep(3);
    goto loop2;
    }
fprintf(stderr, "[Slave]: opened output\n" );

rc = write( out, "S2M\n\0" , 5);
fprintf(stderr, "[Slave]: wrote %d\n", rc );

rc = read( in, buff , sizeof buff);
fprintf(stderr, "[Slave]: read %d:%s\n", rc, buff );
}
/*************************************/
void randsleep(unsigned max)
{
unsigned val;
val = rand();
val %= max;
sleep(val);
return;
}
/*************************************/
int main(void)
{
int rc;

switch (rc=fork()) {
    case -1: exit(1); break;
    case 0: do_slave(); break;
    default: do_master(); break;
    }
exit (0);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

检测程序何时打开 fifo 的相关文章

随机推荐