>시스템 튜토리얼 >리눅스 >Linux 시스템의 명명된 파이프(FIFO)

Linux 시스템의 명명된 파이프(FIFO)

WBOY
WBOY앞으로
2024-02-15 13:40:03571검색

Linux 시스템은 다중 작업의 동시 실행을 지원하는 운영 체제로, 동시에 여러 프로세스를 실행할 수 있어 시스템 활용도와 효율성이 향상됩니다. 그러나 이러한 프로세스 간에 데이터 교환 및 협업이 필요한 경우 신호, 메시지 큐, 공유 메모리, 세마포어 등과 같은 일부 프로세스 간 통신(IPC) 방법을 사용해야 합니다. 그 중 유명한 파이프(FIFO)는 비교적 간단하고 강력한 IPC 방식으로, 두 개 이상의 프로세스가 파일의 내용과 형식에 상관 없이 파일을 통해 데이터를 전송할 수 있도록 해줍니다. 이 기사에서는 유명한 파이프의 생성, 열기, 읽기, 쓰기, 닫기 및 삭제를 포함하여 Linux 시스템의 명명된 파이프(FIFO) 방법을 소개합니다.

Linux 시스템의 명명된 파이프(FIFO)

이름이 없는 파이프 적용의 주요 제한 사항은 이름이 없으므로 선호도가 있는 프로세스 간 통신에만 사용할 수 있다는 것입니다. 이 제한은 이름이 지정된 파이프(이름이 지정된 파이프 또는 FIFO)가 도입된 후에 극복되었습니다. FIFO는 FIFO 파일 형식으로 파일 시스템에 존재하는 연결된 경로 이름을 제공한다는 점에서 파이프와 다릅니다. 이렇게 하면 FIFO를 생성하는 프로세스와 친화력이 없더라도 해당 경로에 접근할 수 있다면 FIFO를 통해(경로에 접근할 수 있는 프로세스와 생성한 프로세스 간) 통신이 가능하다. FIFO) 따라서 FIFO를 통한 상관관계가 없습니다. 프로세스도 데이터를 교환할 수 있습니다. FIFO는 선입선출(선입선출)을 엄격하게 따른다는 점은 주목할 가치가 있습니다. 파이프와 FIFO에서 읽으면 항상 처음부터 데이터가 반환되고, 여기에 쓰면 끝에 데이터가 추가됩니다. lseek()와 같은 파일 위치 작업을 지원하지 않습니다.
파이프의 버퍼는 제한되어 있습니다(파이프 메커니즘은 메모리에 존재하며 파이프가 생성될 때 버퍼에 페이지 크기가 할당됩니다)
파이프라인이 전송하는 것은 형식화되지 않은 바이트 스트림입니다. 이를 위해서는 파이프라인의 판독기와 작성자가 메시지(또는 명령 또는 레코드)로 계산되는 바이트 수 등과 같은 데이터 형식에 미리 동의해야 합니다.

FIFO에는 여러 쓰기 프로세스와 하나의 읽기 프로세스가 있는 경우가 많습니다.

FIFO 개시 규칙:

  1. 현재 열기 작업이 읽기를 위해 FIFO를 여는 것이라면 해당 프로세스가 이미 쓰기를 위해 FIFO를 열었다면 현재 열기 작업은 성공적으로 반환됩니다. 그렇지 않으면 해당 프로세스가 쓰기를 위해 FIFO를 열 때까지 차단될 수 있습니다. 현재 열기 작업 차단 플래그가 설정되어 있음) 또는 성공적으로 반환됩니다(현재 열기 작업에 차단 플래그가 설정되어 있지 않음).
  2. 현재 열기 작업이 쓰기를 위해 FIFO를 여는 것이라면 해당 프로세스가 이미 읽기를 위해 FIFO를 열었다면 현재 열기 작업은 성공적으로 반환됩니다. 그렇지 않으면 해당 프로세스가 읽기를 위해 FIFO를 열 때까지 차단될 수 있습니다. 열기 작업 차단 플래그가 설정됨) 또는 ENXIO 오류가 반환됩니다(현재 열기 작업에 대해 차단 플래그가 설정되지 않음).

한 문장으로 말하자면, 차단 플래그가 설정되고 이를 설정하기 위해 mkfifo가 호출되면 파이프 양쪽 끝의 읽기 및 쓰기가 별도로 열려야 하며 어느 쪽이든 열려 있지 않으면 차단됩니다. 오픈이라고 합니다.

FIFO에서 데이터 읽기:

규칙: 프로세스가 FIFO에서 데이터를 읽기 위해 FIFO 열기를 차단하는 경우 프로세스 내의 읽기 작업을 차단 플래그가 설정된 읽기 작업이라고 합니다. (이제 데이터를 읽기 위해 유명한 파이프를 열고 싶다는 의미입니다!)

FIFO를 열기 위해 프로세스가 쓰고 현재 FIFO에 데이터가 없는 경우(파이프의 양쪽 끝이 설정되었지만 쓰기 끝이 아직 데이터 쓰기를 시작하지 않은 것으로 이해할 수 있습니다!)

  1. 그런 다음 차단 플래그가 설정된 읽기 작업의 경우 항상 차단됩니다(즉, 차단되고 데이터를 기다리고 있습니다. CPU 리소스를 소비하지 않습니다. 이 프로세스 동기화 방법은 CPU에 매우 효율적입니다.)
  2. 차단 플래그를 설정하지 않은 읽기 작업의 경우 -1이 반환되고 현재 errno 값은 EAGAIN이므로 나중에 다시 시도하도록 알려줍니다.

차단 플래그가 설정된 읽기 작업의 경우(위 규칙 참조)
방해하는 이유는 두 가지입니다

  1. FIFO内有数据,但有其它进程在读这些数据
  2. FIFO内没有数据。解阻塞的原因则是FIFO中有新的数据写入,不论信写入数据量的大小,也不论读操作请求多少数据量。

读打开的阻塞标志只对本进程第一个读操作施加作用,如果本进程内有多个读操作序列,则在第一个读操作被唤醒并完成读操作后,其它将要执行的读操作将不再阻塞,即使在执行读操作时,FIFO中没有数据也一样,此时,读操作返回0。

注:如果FIFO中有数据,则设置了阻塞标志的读操作不会因为FIFO中的字节数小于请求读的字节数而阻塞,此时,读操作会返回FIFO中现有的数据量。

向FIFO中写入数据:

约定:如果一个进程为了向FIFO中写入数据而阻塞打开FIFO,那么称该进程内的写操作为设置了阻塞标志的写操作。

对于设置了阻塞标志的写操作:

  1. 当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。如果此时管道空闲缓冲区不足以容纳要写入的字节数,则进入睡眠,直到当缓冲区中能够容纳要写入的字节数时,才开始进行一次性写操作。(PIPE_BUF ==>> /usr/include/linux/limits.h)
  2. 当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。FIFO缓冲区一有空闲区域,写进程就会试图向管道写入数据,写操作在写完所有请求写的数据后返回。

对于没有设置阻塞标志的写操作:

  1. 当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。在写满所有FIFO空闲缓冲区后,写操作返回。
  2. 当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。如果当前FIFO空闲缓冲区能够容纳请求写入的字节数,写完后成功返回;如果当前FIFO空闲缓冲区不能够容纳请求写入的字节数,则返回EAGAIN错误,提醒以后再写;

简单描述下上面设置了阻塞标志的逻辑
设置了阻塞标志

if (buf_to_write then
 if ( buf_to_write > system_buf_left ) //保证写入的原子性,要么一次性把buf_to_write全都写完,要么一个字节都不写!
 then
  block ;
  until ( buf_to_write else
  write ;
 fi
else
 write ; //不管怎样,就是不断写,知道把缓冲区写满了才阻塞
fi

管道写端 pipe_read.c

/pipe_read.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define FIFO_NAME "/tmp/my_fifo"
#define BUFFER_SIZE PIPE_BUF

int main()
{
int pipe_fd;
int res;

int open_mode = O_RDONLY;
char buffer[BUFFER_SIZE + 1];
int bytes = 0;

memset(buffer, '\0', sizeof(buffer));

printf("Process %d opeining FIFO O_RDONLY\n", getpid());
pipe_fd = open(FIFO_NAME, open_mode);
printf("Process %d result %d\n", getpid(), pipe_fd);

if (pipe_fd != -1)
{
do{
res = read(pipe_fd, buffer, BUFFER_SIZE);
bytes += res;
printf("%d\n",bytes);
}while(res > 0);
close(pipe_fd);
}
else
{
exit(EXIT_FAILURE);
}

printf("Process %d finished, %d bytes read\n", getpid(), bytes);
exit(EXIT_SUCCESS);
}

管道读端 pipe_write.c

//pipe_write.c

#include   
#include   
#include   
#include   
#include   
#include   
#include   
  
#define FIFO_NAME "/tmp/my_fifo"  
#define BUFFER_SIZE PIPE_BUF  
#define TEN_MEG (1024 * 100)  
  
int main()  
{  
    int pipe_fd;  
    int res;  
    int open_mode = O_WRONLY;  
  
    int bytes = 0;  
    char buffer[BUFFER_SIZE + 1];  
  
    if (access(FIFO_NAME, F_OK) == -1)  
    {  
        res = mkfifo(FIFO_NAME, 0777);  
        if (res != 0)  
        {  
            fprintf(stderr, "Could not create fifo %s\n", FIFO_NAME);  
            exit(EXIT_FAILURE);  
        }  
    }  
  
    printf("Process %d opening FIFO O_WRONLY\n", getpid());  
    pipe_fd = open(FIFO_NAME, open_mode);  
    printf("Process %d result %d\n", getpid(), pipe_fd);  
  
   //sleep(20);
    if (pipe_fd != -1)  
    {  
        while (bytes if (res == -1)  
            {  
                fprintf(stderr, "Write error on pipe\n");  
                exit(EXIT_FAILURE);  
            }  
            bytes += res;  
        printf("%d\n",bytes);
        }  
        close(pipe_fd);  
    }  
    else  
    {  
        exit(EXIT_FAILURE);  
    }  
  
    printf("Process %d finish\n", getpid());  
    exit(EXIT_SUCCESS);  
}

本文介绍了Linux 시스템의 명명된 파이프(FIFO)的方法,包括有名管道的创建、打开、读写、关闭和删除等方面。通过了解和掌握这些知识,我们可以更好地使用有名管道(FIFO)来实现进程间通信,提高系统的性能和可靠性。当然,Linux 시스템의 명명된 파이프(FIFO)还有很多其他的特性和用法,需要我们不断地学习和探索。希望本文能给你带来一些启发和帮助。

위 내용은 Linux 시스템의 명명된 파이프(FIFO)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 lxlinux.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제