プロセス間の早期コミュニケーション

序文:

1. プロセス間通信は、次の 3 つのカテゴリに分類されます。

初期:名前のないパイプ(pipe) 、名前付きパイプ(fifo)およびシグナル(signal)

System 5 IPC オブジェクト:共有メモリメッセージ キュー、およびセマフォ

ネットワークソケット

2. パイプライン:

パイプは、Linux のプロセス通信の方法です。パイプは、あるプログラムの出力を別のプログラムの入力に直接接続します。Linux のパイプライン通信には、名前付きパイプ、名前なしパイプ、およびパイプ ファイル インジケータ TT の 2 つの主なタイプがあります。

1. 名前のないパイプライン

1. 名前のないパイプの概要:

名前のないパイプは Linux 通信の独自の方法であり、次の特徴があります。

(1) 関係のあるプロセス間(親子プロセスまたは兄弟プロセス)のみ通信可能

(2) 読み出し側と書き込み側が固定されたシンプレックス(一方が受信、もう一方が送信)です。

(3) パイプは特別なファイルとみなすこともでき、その read()、write() およびその他の関数もその読み取りおよび書き込みに使用できますが、どのシステム ファイルにも属さず、システム ファイル内にのみ存在します。メモリ。

モデル:

パイプ関数:

 pipe:创建无名管道
      #include <unistd.h>
        int pipe(int pipefd[2]);
        功能: 
            创建无名管道 
                     
        参数: 
            pipefd[2]:整型数组
               存放两个文件描述符:一个负责读 一个负责写 
                        [0]--->读取 
                        [1]--->写入 
                                        
          返回值: 
               成功返回0 
               失败返回-1,并设置错误码

2. テストコード:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(){
    //制作无名管道需要用到整型数组 ,一个写,一个读
    int pipefd[2];
    
    //创建无名管道 ,返回值为0则创建成功
    int ret=pipe(pipefd);
    if(ret<0){
        perror("pipe");
        return -1;
    }
    
    printf("[0]:%d\n",pipefd[0]);
    printf("[1]:%d\n",pipefd[1]);
    
    //开出父子进程,父子进程依赖无名管道进行通信 
    pid_t pid=fork();//开出父子进程 
    if(pid>0){
       //父进程的操作 :发送信息给子进程
       char buf[50]="";
        while(1){
			//bzero 清空数组内存垃圾值
            bzero(buf,sizeof(buf));
            scanf("%s",buf);
            write(pipefd[1],buf,strlen(buf));
        }
       
    }else if(pid==0){
       //子进程的操作,读取无名管道中的内容
       char buf[50];
       while(1){
           bzero(buf,sizeof(buf));
           read(pipefd[0],buf,sizeof(buf));
           printf("子进程收到:%s\n",buf);
       }
    }else{
        perror("fork");
        exit(-1);
    }
       
    return 0;
}

3. パイプラインの読み書きに関する注意事項

パイプ内にデータがない場合、読み取り操作はブロックされます
パイプにデータを書き込むとき、 Linux は 書き込みのアトミック性を保証しません。パイプ バッファーに空き領域ができるとすぐに、書き込みプロセスは書き込みを試みます。
データをパイプに書き込みます。読み取りプロセスでパイプ バッファー内のデータが読み取られない場合、書き込み操作はブロックされたままになります。
パイプへのデータの書き込みは、パイプの読み取り側が存在する場合にのみ意味を持ちます。それ以外の場合、パイプにデータを書き込むプロセスは
カーネルから送信された SIFPIPE シグナル ( 通常は パイプ破損 エラー )

2. 有名なチャンネル

1. 有名なパイプラインの特徴

名前付きパイプ (FIFO) は名前なしパイプを改良したもので、次の特徴があります。

(1) 無関係な 2 つのプロセス間の通信を実現します。

(2) パイプはパスで指定でき、システム内で可視となり、確立後は 2 つのプロセスが通常のファイルとして読み取りおよび書き込み操作を行うことができます。

(3) FIFO は先入れ先出し規則に厳密に従い、lseek()などの操作 (位置決め) をサポートしません

モデル:

2. テスト:

 

通信方1:

#include <stdio.h>
#include <sys/types.h>//mkfifo头文件
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc,char *argv[]){
    if(argc!=2){
        printf("User:%s <file_name> \n",argv[0]);
        return 0;
    }
    //创建管道文件(利用某一个文件名只能创建一次的特性)
    if(access(argv[1],F_OK)){  //判断argv[1]是否已经存在
            if(mkfifo(argv[1],0666)){
                perror("mkfifo");
                exit(-1);
            }
    }
    
    
    //2>利用有名管道进行进程间通信 
    int fd=open(argv[1],O_RDWR);
    if(fd<0){
        perror("open");
        exit(-1);
    }
    //3>往有名管道里写入数据 
    char buf[50]="";
    while(1){
        bzero(buf,sizeof(buf));
        scanf("%s",buf);
        write(fd,buf,strlen(buf));
        }
    
    return 0;
}

通信方2:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc,char *argv[]){
    if(argc!=2){
        printf("User:%s <file_name> \n",argv[0]);
        return 0;
    }
    //创建管道文件(利用某一个文件名只能创建一次的特性)
    if(access(argv[1],F_OK)){  //判断argv[1]是否已经存在
            if(mkfifo(argv[1],0666)){
                perror("mkfifo");
                exit(-1);
            }
    }
    
    //2>利用有名管道进行进程间通信 
    int fd=open(argv[1],O_RDWR);
    if(fd<0){
        perror("open");
        exit(-1);
    }
    //3>往有名管道里读取数据 
       char buf[50];
       while(1){
           bzero(buf,sizeof(buf));
           read(fd,buf,sizeof(buf));
           printf("%s\n",buf);
       }
    
    return 0;
}

3. 読み取り操作:


三、信号通信

1。概要:

        Signal は、ソフトウェア レベルでの割り込みメカニズムと非同期通信方式のシミュレーションです。シグナルはユーザー空間プロセスとカーネルプロセスの間で直接対話でき、カーネルプロセスはシグナルを使用してどのようなシステムイベントが発生したかをユーザー空間プロセスに通知することもできます。
          プロセスが現在実行されていない場合、シグナルはプロセスが実行を再開するまでカーネルによって保存され、その後プロセスに配信されます。シグナルがプロセスによってブロックされるように設定されている場合、シグナルの配信はブロックが解除されるまで遅延されます。キャンセルされた場合にのみプロセスに渡されます。

2. ライフサイクル:

 3. 信号応答:

(1)シグナルを無視する: シグナルに対して処理は実行されませんが、無視できないシグナルが 2 つあります: SIGKILLSIGSTOP

(2) 信号の捕捉: 信号処理関数を定義し、信号が発生すると、対応する処理関数を実行します。

(3)デフォルト操作の実行: Linux は各信号に対してデフォルト操作を提供します。

4. 信号の検出と処理プロセス:

 

5. 信号の種類:

 一般的に使用される信号:

1) SIGHUP ;--->终端在关闭时,给其下所有的进程发送信号 
2) SIGINT :--->结束进程  就是:ctrl + c 
3) SIGQUIT: --->结束进程  就是:ctrl + \
9) SIGKILL: --->强制杀死进程  不能被注册,不能被忽略 --->signal 
10) SIGUSR1:--->用户自定义信号  --->signal
12) SIGUSR2:--->用户自定义信号  --->signal
14) SIGALRM:-->闹钟信号,用来倒计时,当到0后,触发信号,结束进程 
17) SIGCHLD:--->子进程结束时,给父进程发送的信号 
18) SIGCONT:--->继续进程 
19) SIGSTOP:--->暂停进程: 不能被注册,不能被忽略 --->signal
20) SIGTSTP:-->暂停进程: ctrl + z

6. 信号を送信します。

                1>发送信号 
                   kill
                   #include <sys/types.h>
                   #include <signal.h>
                   int kill(pid_t pid, int sig);
                   功能: 
                        发送信号 
                        
                   参数: 
                           pid:接收信号的进程PID:发送给谁 
                           sig:发送的信号是什么
                           
                   返回值: 
                           成功返回0 
                           失败返回-1,并设置错误码
                           
                2>函数转换类型: 
                    atoi --->char型转int型
                    #include <stdlib.h>
                    int atoi(const char *nptr);
                    功能: 
                          将接收到的char型转化为int型 
                          
                    参数: 
                            nptr:接受到的char型 
                            
                    返回值: 
                            成功返回转化后int型
                            失败返回-1,并设置错误码
                            
                    从左往右进行转换的

7. 信号処理: signal() 関数:

                        信号注册:
                        signal
                        #include <signal.h>
                       typedef void (*sighandler_t)(int);
                       sighandler_t signal(int signum, sighandler_t handler);
                       功能: 
                            信号注册 
                            
                       参数: 
                             signum:需要操作的信号 
                             handler:注册事件 
                                   SIG_IGN:忽略 
                                   SIG_DFL:默认:恢复  
                                   捕捉:注册:执行自己写的一个函数
                                   typedef void (*sighandler_t)(int);--->函数指针
                                   
                       返回值: 
                            成功返回sighandler_t类型 
                            失败返回-1,并设置错误码\

8.タイマー機能:

        一時停止機能、アラーム機能:                  

#include <unistd.h>
            int pause(void);
            功能:
                    将进程挂起(休眠等待唤醒)--->阻塞 
                    唤醒:捕捉信号,执行该信号则解除挂起-->唤醒
               
            参数: 
                   void
                    
            返回值: 
                    成功返回0 
                    失败返回-1,并设置错误码
            
            
            alarm
            #include <unistd.h>
            unsigned int alarm(unsigned int seconds);
            功能: 
                    倒计时(计时器)
                    当倒计时到0时,触发SIGALRM信号,结束进程 
                    
            参数: 
                    seconds:秒数 
                    
            返回值: 
                    第一次调用返回0
                    二次调用以上,返回剩余秒数

9. テスト: コード:

親プロセスが cltr+c 操作を受け取ると、子プロセスは次のように出力します。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
//收到信号后执行的函数,通过信号注册传递
void showMsg(int sig){
        printf("我们要去佤邦发财啦!\n");
}
//捕捉信号
void sendMsg(int sig){
    kill(getppid(),SIGUSR1);
}

int main(){
    //因为操作要开出父子进程:fork 
    pid_t pid=fork();
    if(pid>0){
        //父进程操作
        signal(SIGUSR1,showMsg);
        signal(SIGINT,SIG_IGN);
    }else if(pid==0){
        //子进程的操作
        signal(SIGINT,sendMsg);
    }
    
    while(1){
      //防止过快,显示,也可以用pause()函数  
    }
    return 0;
}

 


おすすめ

転載: blog.csdn.net/apple_71040140/article/details/132510197