3. Operating system - inter-process communication (1) (unnamed pipe (PIPE) and famous pipe (FIFO))

Table of contents

1. Six communication methods

2. Unnamed pipeline (PIPE) and famous pipeline (FIFO)

1. Anonymous pipeline

(1) Features

(2) Use of PIPE

(3) Notes

(4) Code

 2. Famous pipeline (FIFO)

(1) FIFO characteristics

(2) Application of FIFO

(3) Precautions

  (4)read.c

  (5)write.c

3. Signal

1. Order

2. Signal/event generation method

3. Types of signals

4. Pay attention

5. Signal correlation function

 (1) kill (generate a signal, kill a certain process, and signal captures the generated signal)

 (2) signal (used with kill)

 (3)raise

 (4) pause (suspend)

 (5) sigprocmask (blocking/unblocking)

 (6) Signal set operation function cluster

 (7) sigqueue (to whom, the signal sent, the data carried) (a pair with sigaction)

 (8)sigaction

 6. Routine

 (1) Capture the signal in the child process and respond accordingly

 (2) Application of signal blocking

 (3) Application of sigqueue and aigaction

1. Six communication methods

1. Unnamed pipe (PIPE) and named pipe (FIFO)

2. Signal

3. Shared memory of system V-IPC

 4. Message queue of system V-IPC

 5. Semaphore of system V-IPC

 6. Socket

2. Unnamed pipeline (PIPE) and famous pipeline (FIFO)

1. Anonymous pipeline

(1) Features

a. Out at the same time, in at the same time b. Without a name, it cannot be opened with open

c. Only used between relative processes (father-son, brother, grandparent process) d. Cannot use lseek() to locate

(2) Use of PIPE

(3) Notes

a. The parameter in pipe is an array with two integers used to store file descriptors, one is the read end and the other is the write end

b. The figure illustrates the state of the pipeline after the child process is created

 c. pipefd[0] --> read port 

        pipefd[1] --> write port

(4) Code

#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. Famous pipeline (FIFO)

(1) FIFO characteristics

a. It has a name and is stored in the ordinary file system b. You can use open() to get the file descriptor of the FIFO

c. Use unified read( )/write( ) to read and write d. Cannot use lseek( ) to locate

e. With write atomicity, it supports multiple writers to write at the same time without data being trampled on each other

f. First In First Out, the data that is first written into the FIFO is read out first

(2) Application of FIFO

(3) Precautions

a. When the pipeline file is opened, if there is only one party (reader/writer), it will block and wait for the other party to arrive and then open the file at the same time.

 (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;
}

3. Signal

1. Order

kill -l //List the signals in the system

2. Signal/event generation method

(1) User button: the user uses some special character to pass to the terminal, and a signal (event) is generated and delivered to the process

(2) Hardware failure: Process execution error, such as accessing an invalid memory address, at this time, the hardware reports to the kernel first, and then the kernel delivers the event to the process

(3) kill function or command: deliver the required events directly to the process through the function

3. Types of signals

(1) Reliable signal:

(2) Unreliable signal: the signal happens, but it may be lost

 Among them, items 1~31 are unreliable signals, and items 34~64 are reliable signals

4. Pay attention

(1) The signals SIGKILL and SIGSTOP are two special signals that cannot be ignored, blocked or captured

(2) Any process can use the function kill( ) to generate any signal.

(3) The target process receiving the signal responds in the following order:

A) If the signal is blocked, then suspend the signal, do not do anything with it, and wait until it is unblocked. Otherwise go to B.

B) If the signal is captured, then further judge the type of capture:

        B1) If a response function is set, execute the response function.

        B2) If set to ignore, then discard the signal directly. Otherwise go to C.

C) Execute the default action of the signal

(4) The signal function can be inherited to the child process

5. Signal correlation function

(1) kill (generate a signal, kill a certain process, and signal captures the generated signal)

 (2) signal (used with kill)

(3)raise

(4) pause (suspend)

(5) sigprocmask (blocking/unblocking)

 (6) Signal set operation function cluster

(7) sigqueue (to whom, the signal sent, the data carried) (a pair with sigaction)

 The additional number carried must be the following union:

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

(8)sigaction

struct aigaction function

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. Routine

(1) Capture the signal in the child process and respond accordingly

#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) Application of signal blocking

#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;
}

After running, wait for 2 seconds before starting to output here is.....

(3) Application of sigqueue and 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;
}

Guess you like

Origin blog.csdn.net/weixin_45981798/article/details/129758387