LINUX inner-process communication

7669 ワード

プロセス間通信方式
パイプ本
パイプは、ローカルコンピュータの2つのプロセス間の通信のために設計された通信方式であり、パイプが確立されると、実際に2つのファイル記述子が得られ、1つは別の書き込みを読み出す.最も一般的なIPCメカニズムは、PIPEシステムによって呼び出されます.パイプは単工で、データは一方向にしか流れません.双方向通信が必要な場合は、2つのパイプを構築する必要があります.パイプの本質はカーネル内のキャッシュです.
パイプのプロパティ:
  • は、2つのパイプによって双方向のパイプ
  • を作成することができる.
  • パイプは閉塞性であり、プロセスがパイプからデータを読み出すと、データプロセスがなければ
  • を閉塞する.
  • パイプには大きさの制限があり、パイプがいっぱいになってから置くと
  • と報告されます.
  • 不完全配管
  • ライトエンドが閉じるパイプを読むと、すべてのデータが読み取られた後、readは0を返し、ファイルの末尾
  • に達したことを示す.
  • リードが閉じたパイプを書くと、信号SIGPIPEが生成されたばかりで、信号を無視したりキャプチャしたりして処理プログラムから戻ると、errnoがEPIPE
  • に設定されている間にwriteは-1を返します.
    パイプの分類
    匿名パイプ
  • リレーションシッププロセス(親プロセスの各サブプロセス、兄弟プロセスの間)
  • PIPEシステムによって呼び出される
  • パイプはカーネル空間に位置し、実際にはキャッシュ
  • である.
    #include 
    #include 
    #include 
    
    /**
    *Desc:           
    *author:xiao_dingo
    *since:2018-03-07
    *email:[email protected]
    */
    
    char *cmd1[3] = {"/bin/cat","/etc/passwd",NULL};
    char *cmd2[3] = {"/bin/grep","root",NULL};
    
    int main(void){
    
            int fd[2];
            if(pipe(fd) < 0){
                    perror("pipe error");
            }
    
            int i = 0;
            pid_t pid;
            for(;i < 2; i++){
                    pid = fork();
                    if(pid < 0){
                            perror("fork error");
                            exit(1);
                    }else if(pid == 0){//child process
    
                            if(i == 0){
                                    close(fd[0]);
    
                                    //              
                                    if(dup2(fd[1],STDOUT_FILENO) != STDOUT_FILENO){
                                    perror("dup2 error");
                                    }
                                    close(fd[1]);
                                    if(execvp(cmd1[0],cmd1) < 0){
                                            perror("execvp error");
                                            exit(1);
                                    }
                                    break;
                            }
                            if(i == 1){
                                    close(fd[1]);
    
                                    //              
                                    if(dup2(fd[0],STDIN_FILENO) != STDIN_FILENO){
                                    perror("dup2 error");
                                    }       
                                    close(fd[0]);
                                    if(execvp(cmd2[0],cmd2) < 0){
                                            perror("execvp error");
                                            exit(1);
                                    }
                                    break;
                            }
                    }else{//parent process
                            if(i == 1){
                                    close(fd[0]);
                                    close(fd[1]);
                                    wait(NULL);
                                    wait(NULL);
                            }
                    }
            }
            exit(0);
    }
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    /**
    *Desc:         
    *author:xiao_dingo
    *since:2018-03-08
    *email:[email protected]
    */
    
    void sig_handler(int signo){
            if(signo == SIGPIPE){
                    printf("sigpipe occured
    "); } } void main(void){ int fd[2]; if(pipe(fd) < 0){ perror("pipe error"); exit(1); } pid_t pid; if((pid = fork()) < 0){ perror("fork error"); exit(1); }else if(pid > 0){//parent process sleep(5); close(fd[0]); if(signal(SIGPIPE,sig_handler) == SIG_ERR){ perror("signal sigpipe error"); exit(1); } char *s = "1234"; if(write(fd[1],s,sizeof(s)) != sizeof(s)){ fprintf(stderr,"%s,%s
    ",strerror(errno),(errno == EPIPE) ? "EPIPE" : ",UNKNOW"); } }else{//child process close(fd[0]); close(fd[1]); } }

    名前付きパイプ(FIFO)
  • の2つの関係のない間の通信は、名前付きパイプを介してデータ伝送することができ、本質はカーネル内のキャッシュであり、ファイルシステムには特殊なデバイスファイル(パイプファイル)で存在する.ファイルシステム内のパイプファイルには、インデックスブロックが1つしかありません.ファイルパスは格納されません.データブロックはありません.すべてのデータはカーネルに格納されます.
  • システム呼び出しmkfifoにより
  • を作成する
  • 名前付きパイプは、読み取りと書き込みを同時に開く必要があります.そうしないと、ブロック
  • に入ります.
  • #include 
    #include 
    int mkfifo(const char* pathname,mode_t mode);

    メッセージキュー
    System v IPCオブジェクト(メッセージキュー、共有メモリ、信号量)は、ファイルシステムではなくカーネルに存在し、パイプやリリースのようにカーネルによって制御されるのではなく、ユーザによってリリースを制御します(IPCオブジェクトのライフサイクルを管理します).IPCオブジェクトは識別子によって参照されアクセスされ、すべてのIPCオブジェクトはカーネル空間に一意の識別IDを有し、ユーザ空間における一意の識別はKeyと呼ばれる.
    メッセージキューのプロパティ
  • メッセージキューは、カーネル内のチェーンテーブル
  • である.
  • ユーザプロセスがカーネルにデータを転送すると、カーネルはユーザID、グループID、読み書きプロセスのID、優先セットなどの関連情報を再追加し、メッセージ
  • と呼ばれるパケットを打つ.
  • は、1つまたは複数のプロセスがメッセージキューにメッセージを書き込み、メッセージを読むことを許可するが、1つのメッセージは1つのプロセスによってしか読み取ることができず、読み取りが完了すると自動的に
  • を削除する.
  • メッセージキューは、一定のFIFO特性を有し、メッセージは順番にキューに送信することもできるし、いくつかの異なる方法でキューから読み出すこともできる.メッセージキューは、カーネルにおいて
  • を一意のIPC識別IDで表す.
  • メッセージキューの実装には、キューの作成とオープン、メッセージの送信、メッセージの読み取り、メッセージキューの制御の4つの動作
  • が含まれる.
  • linuxシステム表示コマンドipcs削除ipcrm
  • #include 
    int msgget(key_t key,int flag);//  
    int msgctl(int msgid,int cmd,struct msgid_ds *buf);//  
    int msgsnd(int magid,const void *ptr,szie_t nbytes,int flag);//  
    ssize_t msgrvc(int msgqid,void *ptr,size_t nbytes,long type,int flag);//  

    共有メモリ
    共有メモリは、システム内の2つ以上のプロセスが同じメモリ領域を共有し、データがクライアントプロセスとサーバプロセス間でコピーされる必要がないため、共有メモリは通信速度が最も速いIPCです.実装のメカニズムは、1つのプロセスがシステムで共有メモリ空間を開くことを申請し、この共有メモリ空間を使用する各プロセスがそれぞれこの共有メモリ空間を開き、このメモリ空間を自分のプロセス空間にマッピングすることで、各プロセスがこの共有メモリ空間を共同で使用することができます.自分のプロセスアドレス空間のメモリを使用するように共有メモリ空間を実現するには、カーネルは多くの仕事をしています.例えば、共有メモリブロックごとに「身分証明書」を配布したり、ユーザープロセスが共有メモリをそれぞれのアドレス空間にマッピングしたり、プロセスが申請した後に共有メモリとプロセスアドレス空間を離脱したりします.そして、適切な時に共有メモリを削除し、作成可能な状態に戻す.ユーザは共有メモリを用いてプロセス間の通信を実現し,実際にはカーネルが提供するサービスを用いて共有メモリの確立,マッピング,離脱,削除などを完了する.確立とマッピングに成功すると、プロセス間で共有メモリを介してデータのインタラクションが実現されます.
    カーネルが提供するサービス
    /**
    *shmget             
    *        key      ,          shmflg    IPC_CREAT           size        。  key           ,                ,     。
    *
    */
    int shmget(key_t key, size_t size, int shmflg);
    /**
    *                         ,               。                          。
    *shmid     shmget       ,shmaddr                           ,              ,     NULL ,            。shmflg       shmaddr      , shmaddr  NULL          ,       0
    */
    void *shmat(int shmid,const void* shmaddr,int shmflg);
    /**
    *                           。shmaddr               ,    shmat       
    */
    int shmdt(const void* shmaddr);
    /**
    *            ,                       ,                         。  cmd    IPC_RMID,    shmid           , buf                    ,           0
    */
    int shmctl(int shmid, int cmd, struct shmid_ds *buf);

    プロセス信号量
    プロセス間のhuchiと同期に用いられ、各共有リソースは1つの信号量に対応し、大量の共有リソースの操作を容易にするために信号量セットを導入し、すべての情報量に対して一度に操作することができ、信号量セットのすべての操作に対してすべての成功を要求することができ、一部の成功を要求することができる.これは特殊な変数であり、信号の待機と送信の2つの操作しか許可されていません.
  • P(信号量変数sv):待機.svが0より大きい場合は、svを小さくします.svが0の場合、このプロセスの実行が保留されます.
  • V(信号量変数sv):信号を送信します.プロセスがsvを待機している場合は、実行を再開します.保留待ちsvが行われていない場合は、svを増やします.
  • #include  
    /**
    *
    *
    */
    int semget(key_t key,int nsems,int semflg);