LINUX inner-process communication
プロセス間通信方式
パイプ本
パイプは、ローカルコンピュータの2つのプロセス間の通信のために設計された通信方式であり、パイプが確立されると、実際に2つのファイル記述子が得られ、1つは別の書き込みを読み出す.最も一般的なIPCメカニズムは、PIPEシステムによって呼び出されます.パイプは単工で、データは一方向にしか流れません.双方向通信が必要な場合は、2つのパイプを構築する必要があります.パイプの本質はカーネル内のキャッシュです.
パイプのプロパティ:は、2つのパイプによって双方向のパイプ を作成することができる.パイプは閉塞性であり、プロセスがパイプからデータを読み出すと、データプロセスがなければ を閉塞する.パイプには大きさの制限があり、パイプがいっぱいになってから置くと と報告されます.不完全配管 ライトエンドが閉じるパイプを読むと、すべてのデータが読み取られた後、readは0を返し、ファイルの末尾 に達したことを示す.リードが閉じたパイプを書くと、信号SIGPIPEが生成されたばかりで、信号を無視したりキャプチャしたりして処理プログラムから戻ると、errnoがEPIPE に設定されている間にwriteは-1を返します.
パイプの分類
匿名パイプリレーションシッププロセス(親プロセスの各サブプロセス、兄弟プロセスの間) PIPEシステムによって呼び出される パイプはカーネル空間に位置し、実際にはキャッシュ である.
名前付きパイプ(FIFO)の2つの関係のない間の通信は、名前付きパイプを介してデータ伝送することができ、本質はカーネル内のキャッシュであり、ファイルシステムには特殊なデバイスファイル(パイプファイル)で存在する.ファイルシステム内のパイプファイルには、インデックスブロックが1つしかありません.ファイルパスは格納されません.データブロックはありません.すべてのデータはカーネルに格納されます. システム呼び出しmkfifoにより を作成する名前付きパイプは、読み取りと書き込みを同時に開く必要があります.そうしないと、ブロック に入ります.
メッセージキュー
System v IPCオブジェクト(メッセージキュー、共有メモリ、信号量)は、ファイルシステムではなくカーネルに存在し、パイプやリリースのようにカーネルによって制御されるのではなく、ユーザによってリリースを制御します(IPCオブジェクトのライフサイクルを管理します).IPCオブジェクトは識別子によって参照されアクセスされ、すべてのIPCオブジェクトはカーネル空間に一意の識別IDを有し、ユーザ空間における一意の識別はKeyと呼ばれる.
メッセージキューのプロパティメッセージキューは、カーネル内のチェーンテーブル である.ユーザプロセスがカーネルにデータを転送すると、カーネルはユーザID、グループID、読み書きプロセスのID、優先セットなどの関連情報を再追加し、メッセージ と呼ばれるパケットを打つ.は、1つまたは複数のプロセスがメッセージキューにメッセージを書き込み、メッセージを読むことを許可するが、1つのメッセージは1つのプロセスによってしか読み取ることができず、読み取りが完了すると自動的に を削除する.メッセージキューは、一定のFIFO特性を有し、メッセージは順番にキューに送信することもできるし、いくつかの異なる方法でキューから読み出すこともできる.メッセージキューは、カーネルにおいて を一意のIPC識別IDで表す.メッセージキューの実装には、キューの作成とオープン、メッセージの送信、メッセージの読み取り、メッセージキューの制御の4つの動作 が含まれる. linuxシステム表示コマンドipcs削除ipcrm
共有メモリ
共有メモリは、システム内の2つ以上のプロセスが同じメモリ領域を共有し、データがクライアントプロセスとサーバプロセス間でコピーされる必要がないため、共有メモリは通信速度が最も速いIPCです.実装のメカニズムは、1つのプロセスがシステムで共有メモリ空間を開くことを申請し、この共有メモリ空間を使用する各プロセスがそれぞれこの共有メモリ空間を開き、このメモリ空間を自分のプロセス空間にマッピングすることで、各プロセスがこの共有メモリ空間を共同で使用することができます.自分のプロセスアドレス空間のメモリを使用するように共有メモリ空間を実現するには、カーネルは多くの仕事をしています.例えば、共有メモリブロックごとに「身分証明書」を配布したり、ユーザープロセスが共有メモリをそれぞれのアドレス空間にマッピングしたり、プロセスが申請した後に共有メモリとプロセスアドレス空間を離脱したりします.そして、適切な時に共有メモリを削除し、作成可能な状態に戻す.ユーザは共有メモリを用いてプロセス間の通信を実現し,実際にはカーネルが提供するサービスを用いて共有メモリの確立,マッピング,離脱,削除などを完了する.確立とマッピングに成功すると、プロセス間で共有メモリを介してデータのインタラクションが実現されます.
カーネルが提供するサービス
プロセス信号量
プロセス間のhuchiと同期に用いられ、各共有リソースは1つの信号量に対応し、大量の共有リソースの操作を容易にするために信号量セットを導入し、すべての情報量に対して一度に操作することができ、信号量セットのすべての操作に対してすべての成功を要求することができ、一部の成功を要求することができる.これは特殊な変数であり、信号の待機と送信の2つの操作しか許可されていません. P(信号量変数sv):待機.svが0より大きい場合は、svを小さくします.svが0の場合、このプロセスの実行が保留されます. V(信号量変数sv):信号を送信します.プロセスがsvを待機している場合は、実行を再開します.保留待ちsvが行われていない場合は、svを増やします.
パイプ本
パイプは、ローカルコンピュータの2つのプロセス間の通信のために設計された通信方式であり、パイプが確立されると、実際に2つのファイル記述子が得られ、1つは別の書き込みを読み出す.最も一般的なIPCメカニズムは、PIPEシステムによって呼び出されます.パイプは単工で、データは一方向にしか流れません.双方向通信が必要な場合は、2つのパイプを構築する必要があります.パイプの本質はカーネル内のキャッシュです.
パイプのプロパティ:
パイプの分類
匿名パイプ
#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)
#include
#include
int mkfifo(const char* pathname,mode_t mode);
メッセージキュー
System v IPCオブジェクト(メッセージキュー、共有メモリ、信号量)は、ファイルシステムではなくカーネルに存在し、パイプやリリースのようにカーネルによって制御されるのではなく、ユーザによってリリースを制御します(IPCオブジェクトのライフサイクルを管理します).IPCオブジェクトは識別子によって参照されアクセスされ、すべてのIPCオブジェクトはカーネル空間に一意の識別IDを有し、ユーザ空間における一意の識別はKeyと呼ばれる.
メッセージキューのプロパティ
#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つの操作しか許可されていません.
#include
/**
*
*
*/
int semget(key_t key,int nsems,int semflg);