3. 운영 체제 - 프로세스 간 통신(1)(이름 없는 파이프(PIPE) 및 유명한 파이프(FIFO))

목차

1. 6가지 커뮤니케이션 방식

2. 익명 파이프라인(PIPE) 및 유명 파이프라인(FIFO)

1. 익명 파이프라인

(1) 특징

(2) PIPE의 사용

(3)주의 사항

(4) 코드

 2. 유명한 파이프라인(FIFO)

(1) FIFO 특성

(2) FIFO 적용

(3) 주의사항

  (4)read.c

  (5)write.c

셋째, 신호

1. 주문

2. 시그널/이벤트 발생 방식

3. 신호의 종류

4. 주의

5. 신호 상관관계 기능

 (1) kill(시그널을 생성하고, 특정 프로세스를 죽이고, 시그널이 생성된 시그널을 캡처함)

 (2) 신호(kill과 함께 사용)

 (3) 올리다

 (4) 일시 중지

 (5) sigprocmask(차단/차단 해제)

 (6) 시그널 세트 동작 기능 클러스터

 (7) sigqueue(누구에게 보내는 신호, 전송되는 데이터)(sigaction과 한 쌍)

 (8)시그액션

 6. 루틴

 (1) 자식 프로세스에서 신호를 캡처하고 그에 따라 응답

 (2) 신호 차단 적용

 (3) sigqueue 및 aigaction의 적용

1. 6가지 커뮤니케이션 방식

1. 명명되지 않은 파이프(PIPE) 및 명명된 파이프(FIFO)

2. 신호

3. 시스템 V-IPC의 공유 메모리

 4. 시스템 V-IPC의 메시지 큐

 5. 시스템 V-IPC의 세마포어

 6. 소켓

2. 익명 파이프라인(PIPE) 및 유명 파이프라인(FIFO)

1. 익명 파이프라인

(1) 특징

a.out at the same time, in at the same time b. 이름이 없으면 열기로 열 수 없습니다.

c. 상대 프로세스(아버지-아들, 형제, 조부모 프로세스) 사이에서만 사용됨 d. lseek()를 사용하여 위치를 찾을 수 없음

(2) PIPE의 사용

(3)주의 사항

a. 파이프의 매개변수는 파일 디스크립터를 저장하는 데 사용되는 두 개의 정수가 있는 배열이며, 하나는 읽기 끝이고 다른 하나는 쓰기 끝입니다.

b. 그림은 자식 프로세스가 생성된 후 파이프라인의 상태를 보여줍니다.

 c.pipefd[0] --> 읽기 포트 

        pipefd[1] --> 쓰기 포트

(4) 코드

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

char * buf  = NULL ; 
int pipefd[2]

void f(void)
{
    while(1)
    {
        printf("父进程*请输入:\n");
        fgets(buf , 1024 , stdin );
        int ret_val = write( pipefd[1] , buf ,  strlen(buf)+1 );
        printf("成功写入:%d字节 \n" , ret_val );

        ret_val = read( pipefd[0] , buf , 1024 );
        printf("父进程*成功读取:%d字节  内容:%s \n" , ret_val , buf );
    }
}

void s(void)
{
    while(1)
    {
        int ret_val = read( pipefd[0] , buf , 1024 );
        printf("子进程*成功读取:%d字节  内容:%s \n" , ret_val , buf );

        printf("子进程*请输入:\n");
        fgets(buf , 1024 , stdin );
        ret_val = write( pipefd[1] , buf , strlen(buf)+1 );
        printf("成功写入:%d字节 \n" , ret_val );
    }
}

int main(int argc, char const *argv[])
{    
    if(pipe( pipefd))
    {
        perror("pipe error");
        return -1 ;
    }
    buf = calloc(1, 1024);
    int pid = fork();
    if ( pid > 0 )
    {
        f();
    }
    else if (pid == 0)
    {
        s();
    }
    else 
    {
        perror("fork error ");
    }  
    return 0;
}

 2. 유명한 파이프라인(FIFO)

(1) FIFO 특성

a. 이름이 있고 일반 파일 시스템에 저장됩니다. b. open()을 사용하여 FIFO의 파일 설명자를 얻을 수 있습니다.

c. 통합 읽기( )/쓰기( )를 사용하여 읽기 및 쓰기 d. lseek( )를 사용하여 위치를 찾을 수 없음

e. 쓰기 원자성으로 데이터가 서로 짓밟히지 않고 여러 작성자가 동시에 쓰기를 지원합니다.

f.선입선출(First In First Out), FIFO에 가장 먼저 쓰여진 데이터를 먼저 읽는다.

(2) FIFO 적용

(3) 주의사항

a.파이프라인 파일이 열릴 때 한 쪽(reader/writer)만 있으면 차단하고 상대방이 도착할 때까지 기다렸다가 동시에 파일을 엽니다.

 (4)read.c

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

#define FIFO_PATH "/tmp/my_fifo"

int main(int argc, char const *argv[])
{
    // 创建管道文件
    if( access(FIFO_PATH, F_OK)) // 判断管道文件是否已存在 如果存在则返回 0 否则 -1 
    {
        if( mkfifo(FIFO_PATH , 0666 )) // 创建
        {
            perror("mkfifo error");
            return -1 ;
        }
    }

    printf("管道文件创建成功!! \n") ;


    // 打开管道文件
    int fd_fifo = open(FIFO_PATH, O_RDONLY );
    if (-1 == fd_fifo)
    {
        perror("open error");
        return -1 ;
    }
    printf("管道文件打开成功!! \n") ;
    

    // 读取信息
    char buf[128]= {0};
    int ret_val = read(fd_fifo , buf  , sizeof( buf ));
    printf("成功读取:%d 字节 内容:%s \n" , ret_val , buf );

    // 关闭文件
    close(fd_fifo);


    return 0;
}

(5)write.c

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

#define FIFO_PATH "/tmp/my_fifo"

int main(int argc, char const *argv[])
{
    // 创建管道文件
    if( access(FIFO_PATH, F_OK)) // 判断管道文件是否已存在 如果存在则返回 0 否则 -1 
    {
        if( mkfifo(FIFO_PATH , 0666 )) // 创建
        {
            perror("mkfifo error");
            return -1 ;
        }
    }
    
    printf("管道文件创建成功!! \n") ;

    // 打开管道文件
    int fd_fifo = open(FIFO_PATH, O_WRONLY );
    if (-1 == fd_fifo)
    {
        perror("open error");
        return -1 ;
    }
    printf("管道文件打开成功!! \n") ;
    

    // 写入信息
    int ret_val = write(fd_fifo , "hello Even" , sizeof("hello Even"));
    printf("成功写入:%d 字节 \n" , ret_val);

    // 关闭文件
    close(fd_fifo);

    return 0;
}

셋째, 신호

1. 주문

kill -l //시스템의 신호 나열

2. 시그널/이벤트 발생 방식

(1) 사용자 버튼: 사용자가 어떤 특수 문자를 사용하여 단말기에 전달하고 신호(이벤트)를 생성하여 프로세스에 전달합니다.

(2) 하드웨어 장애: 유효하지 않은 메모리 주소에 접근하는 등의 프로세스 실행 오류로, 이때 하드웨어는 먼저 커널에 보고한 다음 커널이 이벤트를 프로세스에 전달한다.

(3) kill 기능 또는 명령: 기능을 통해 필요한 이벤트를 프로세스에 직접 전달

3. 신호의 종류

(1) 신뢰할 수 있는 신호:

(2) 신뢰할 수 없는 신호: 신호가 발생하지만 손실될 수 있음

 이 중 항목 1~31은 신뢰할 수 없는 신호이고 항목 34~64는 신뢰할 수 있는 신호입니다.

4. 주의

(1) SIGKILL 및 SIGSTOP 신호는 무시, 차단 또는 캡처할 수 없는 두 가지 특수 신호입니다.

(2) 모든 프로세스는 kill( ) 함수를 사용하여 신호를 생성할 수 있습니다.

(3) 신호를 받은 대상 프로세스는 다음과 같은 순서로 응답합니다.

A) 신호가 차단되면 신호를 일시 중지하고 아무 것도 하지 말고 차단이 해제될 때까지 기다리십시오. 그렇지 않으면 B로 이동합니다.

B) 신호가 캡처되면 캡처 유형을 추가로 판단합니다.

        B1) 응답기능이 설정되어 있으면 응답기능을 실행한다.

        B2) 무시로 설정하면 신호를 직접 폐기합니다. 그렇지 않으면 C로 이동합니다.

C) 신호의 기본 동작 실행

(4) 신호 기능을 자식 프로세스에 상속할 수 있습니다.

5. 신호 상관관계 기능

(1) kill(시그널을 생성하고, 특정 프로세스를 죽이고, 시그널이 생성된 시그널을 캡처함)

 (2) 신호(kill과 함께 사용)

(3) 올리다

(4) 일시 중지

(5) sigprocmask(차단/차단 해제)

 (6) 시그널 세트 동작 기능 클러스터

(7) sigqueue(누구에게 보내는 신호, 전송되는 데이터)(sigaction과 한 쌍)

 수행되는 추가 번호는 다음 조합이어야 합니다.

union sigval
{
    int sigval_int;
    void * sigval_prt;
};

(8)시그액션

struct aigaction 함수

struct sigaction
{
    void (*sa_handler)(int);
    void (*sa_sigaction)(int, siginfo_t *, void *);
    sigset_t sa_mask;
    int sa_flags;
    void (*sa_restorer)(void);
};
void (*sa_sigaction)(int, siginfo_t *, void *);

6. 루틴

(1) 자식 프로세스에서 신호를 캡처하고 그에 따라 응답

#include <stdio.h>
#include <sys/types.h>
#include <signal.h>

void func(int arg)
{
    printf("这里是信号响应函数 %d \n" , arg );//信号响应
}

int main(int argc, char const *argv[])
{
    int pid = fork();
    int i = 0 ;
    
    if (pid > 0 )
    {
        printf("这里是父进程 \n " );
        sleep(3);
        printf("猎杀时间到了..。 \n " );
        sleep(1);
        kill(pid , 4 );        //产生信号
    }
    else if (pid == 0 )
    {
        signal( 4 , func);//捕获信号
        while(1)
        {
            printf("这里是子进程 : %d \n ", i++ );
            sleep(1);
        }
    }
    return 0;
}

 (2) 신호 차단 적용

#include <stdio.h>
#include <sys/types.h>
#include <signal.h>

void func(int arg)
{
    printf("这里是信号响应函数 %d \n" , arg );
}

int main(int argc, char const *argv[])
{
    // 设置信号响应的函数
    signal( 3 , func );
    signal( 4 , func );

    // 初始化信号集
    sigset_t set ;
    sigemptyset( &set ); // 将信号集清空
    sigaddset( &set , 3 ); // 将指定的一个信号添加到信号集中
    sigaddset( &set , 4 ); // 将指定的一个信号添加到信号集中

    // 设置阻塞信号集中的信号
    sigprocmask(SIG_SETMASK , &set , NULL ); // 把信号集中的信号设置为阻塞状态

    // 给自己发送 3.4 号信号
    raise(3);
    raise(4);
    sleep(2);

    // 解除阻塞
    sigprocmask(SIG_UNBLOCK , &set , NULL ); // 把信号集中的信号设置为阻塞状态

    return 0;
}

실행 후 출력을 시작하기 전에 2초 동안 기다리십시오. 여기서는.....

(3) sigqueue 및 aigaction의 적용

#include <stdio.h>
#include <signal.h>
#include <strings.h>
#include <sys/types.h>
#include <unistd.h>


void func(int sig, siginfo_t * info , void * arg )
{
    printf("sig:%d , info: %s  arg:%s \n" , sig , (char * )info->si_ptr , (char*)arg );
}

int main(int argc, char const *argv[])
{

    // 定义ACT结构体并设置其信息
    struct sigaction act ;
    bzero(&act , sizeof(act)); // 清空结构体
    act.sa_sigaction = func ;
    act.sa_flags |= SA_SIGINFO ;//使用拓展信号函数而不是标准响应函数

    // 设置捕获的信号响应函数
    if( sigaction( 3 , &act, NULL ))//将信号捕获函数设置号
    {
        perror("设置捕获失败!!");
        return -1 ;
    }

    // 设置好携带的参数
    union sigval value;
    value.sival_int = 1024 ; // 设置整型数组
    value.sival_ptr = "Hello Even"; // 设置一个地址(指针)可以是任意类型的指针


    // 发送信号
    pid_t pid = getpid( );
    if(sigqueue(pid  ,  3 , value))//发送信号,成功是0,失败是-1
    {
        perror("发送信号失败!!");
        return -1 ;
    }
    printf("发送信号成功!!\n"); 
    sleep(1);

    return 0;
}

추천

출처blog.csdn.net/weixin_45981798/article/details/129758387