3. オペレーティングシステム - プロセス間通信 (1) (名前のないパイプ (PIPE) と有名なパイプ (FIFO))

目次

1. 6つのコミュニケーション方法

2.無名のパイプライン(PIPE)と有名なパイプライン(FIFO)

1.匿名パイプライン

(1) 特長

(2) パイプの使用

(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. 同時に出て、同時に入る b. 名前がないとopenで開けない

c. 相対プロセス (父子プロセス、兄弟プロセス、祖父母プロセス) 間でのみ使用されます d. lseek() を使用して位置を特定することはできません

(2) パイプの使用

(3)注意点

a. パイプ内のパラメーターは、ファイル記述子を格納するために使用される 2 つの整数を含む配列であり、1 つは読み取り側で、もう 1 つは書き込み側です。

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. 統一された read( )/write( ) を使用して読み書きする d. lseek( ) を使用して検索できない

e. 書き込みアトミシティにより、複数のライターがデータを互いに踏みにじることなく同時に書き込むことができます

f. First In First Out、FIFO に最初に書き込まれたデータが最初に読み出されます。

(2) FIFO の適用

(3) 注意事項

a. パイプライン ファイルが開かれるとき、当事者 (リーダー/ライター) が 1 つしかない場合は、ブロックして相手が到着するのを待ってから、同時にファイルを開きます。

 (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 つの特別なシグナルです。

(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)シグアクション

構造体 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