プロセス間通信(IPC)
これに先立ち、私たちは、オペレーティングシステムがユーザーにプロセス間通信を提供するために、理由を理解する必要がありますか?
栗のために、なぜ我々は非常に滑らかで、他の人々と接続することができますか?A:空気は音の媒体広がりがあるので。さて、あなたが独自の仮想アドレス空間を操作している独立プロセスの間に、類推を見ることができ、それは他のプロセスと直接通信することはできません。二つの独立した事業体の間には、公共メディアが存在しない場合、彼らは通信しません、オペレーティングシステムは、このような公共の媒体を提供することにあります。
通信シナリオ:データ転送、データ共有、データ制御
プロセス間の通信4つあり:パイプ、共有メモリ、メッセージキュー、セマフォ
、パイプ1
導管は、本質的にカーネルバッファであり、同じ部分にアクセスする複数のプロセスを介して通信用バッファ。
カテゴリーパイプ:匿名パイプと名前付きパイプ
(1)匿名パイプ
カーネルにおけるプロセスのシステムコールは、パイプラインを作成し、呼び出しがパイプラインを操作するためのハンドルを返し、このパイプラインは他の識別子が存在しない、それだけで操作ハンドルによってアクセスすることができます。唯一のパイプラインを操作するためのハンドルを取得する方法で子供が親のコピーし、同じバッファをアクセスするため、関連するプロセス間通信のためのしたがって、唯一の匿名のパイプ、。そして、前に作成された子プロセスを作成してください。
演算パイプラインハンドル:2つのファイルディスクリプタ。
疑問は、なぜ2を持っていますか?実際には、私たちの日常生活と、このパイプラインは少し1のうちに、などです。しかし、Linuxの下で我々のデータの読み出し、データを書き込むための1のための導管。
関数:INTパイプ(int型pipefd [2
])-----> INT pipefd [2]パイプ(pipefd) int型の配列が戻りpipefd介して2つの要素の配列パスの最初のアドレスがあることを意味2つの動作のハンドル。前記
pipefd [0] -データパイプラインの読み取りに使用されている
pipefd [1] -パイプラインにデータを書き込むため
戻り値:成功時に0を返し、失敗すると-1
例:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int pid=0;
int pipefd[2];
int ret=pipe(pipefd); //创建管道应该在创建子进程之前
if(ret<0)
{
perror("pipe error\n");
return -1;
}
pid=fork(); //创建进程
if(pid==0) //子进程读数据
{
char buf[1024]={0};
int ret=read(pipefd[0],buf,1023);
if(ret<0)
{
perror("read error\n");
return -1;
}
printf("child read data:[%s]\n",buf);
}
else //父进程写数据
{
char *ptr="cold day";
int ret=write(pipefd[1],ptr,strlen(ptr));
if(ret<0)
{
perror("write error\n");
return -1;
}
}
}
結果:
あなたが見ることができ、子と親プロセスは、データの書き込みデータが一致しているお読みください。
** 1)**あなたは親プロセスをさせた場合、その睡眠(5)?次に何が起こりますか?実際には、5秒開始する前に、親プロセスがデータを生成していなかったので、パイプラインは何のデータもないだろうと、この手段は、子がデータがあるまで、それはブロックされます時に読み込ま
パイプラインがデータでいっぱいです** 2)**、書き込みデータが読み出されるまで、書き込みデータブロックに進み
、次の図に、私たちは子供の睡眠に5秒をしましょう
if(pid==0) //子进程读数据
{
sleep(5);
char buf[1024]={0};
........
書き込みデータに親プロセスをしようと、データの長さの合計を算出し、
else //父进程写数据
{
int pipe_size=0; //定义起始数据长度为0
while(1)
{
char *ptr="cold day";
int ret=write(pipefd[1],ptr,strlen(ptr));
if(ret<0)
{
perror("write error\n");
return -1;
}
}
pipe_size+=ret; //写入的数据长度总和
printf("write data:%d\n",pipe_size); //打印总共写了多少
}
プログラムの実行は、子供がそのデータを読み始めた、その結果で見てみましょうが、(出力形式に対する制御は、ここで良いではない、子供が目覚め、後にタイムスライス、その後、親プロセスがデータを書き込んで、最初の5秒間スリープします)私を許して:
子供が読書を開始したときの結果はまた、65536親が書いた、私たちの推測を確認します。
** 3)**パイプのすべての書き込み側が閉じている場合は、パイプラインをブロックしない読み取り後のデータを読み取るが、書き込みに誰がないことを示す0を返します(0を返しますが、意味を持たない言葉を)読み続けます
* * 4)**パイプのすべての読み取り端が書き込みデータが書き込まれたとき、閉じている場合、それは例外をトリガする、プロセスが終了する
私たちは、親プロセスの読み取り終了を閉じて示すように、プロセスが予期せず終了します。
書き込みデータサイズがよりPIPE_BUF = 4096サイズ以下であれば5 **)**読み取る場合、パイプラインは、アトミック動作を保証することができます。
これらは、私たちがパイプラインについて話している5つの特性です。
相互に排他的:1つだけ、運用データのセキュリティを実現するための操作に重要なリソース・データ・ストリームを実行することができ、安全なデータの操作を確実
同期:ストリートタイミング合理性のリソースへのアクセスを実現するために、タイミングによって判断を
(2)の名前パイプライン
名前付きパイプ:カーネルバッファ配管ファイルシステムに見られる片識別子有する
特性:任意のプロセスは、同じホスト間通信に使用することができる
。注:名前付きパイプ場合ために読み取り専用オープンそれがために、他のプロセスによってパイプラインファイルまでブロックします方法を書くオープン
名前付きパイプをする場合の唯一の方法書くために他のプロセスによってパイプラインファイルまでブロックします開いた道読みオープン
int型はmkfifo(のconstのchar *のパス名:機能を 、mode_tモード)
パス名:パス名パイプライン
モード:操作する権限パイプラインファイル
戻り値:成功したリターン0、-1失敗
デモ以下は、名前付きパイプの基本的な操作を示しています。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errono.h>
#include <fcntl.h>
#include <sys/stat.h>
int main()
{
char *file="./test.fifo";
int ret=mkfifo(file,0664); //创建一个管道
if(ret<0)
{
if(errno!=EEXIST) //说明是其他方面的报错
{
perror("mkfifo error");
return -1;
}
}
int fd=open(file,O_RDWR); //以可读可写方式打开这个文件
if(fd<0)
{
perror("open error");
return -1;
}
printf("open success\n");
return 0;
}
私たちは、コンパイル時にコードが正常にコンパイルされました
図2に示すように、共有メモリ
共有メモリ:使用してプロセス間のデータ共有
特性:プロセス間通信最速の方法
:原則達成するために、
カーネルに特定した物理メモリ内のスペースを開く1)を、この空間である
)ページによって、このスペースを2それらの仮想アドレス空間にマップする
仮想メモリアドレスによって行わ3)動作
4)との間の関連付け削除
、共有メモリを削除5)
- 他の共有メモリプロセス間通信と比較して、通信処理において、データは、最速回より少ないユーザーモードとカーネルモードをコピーし、そのためです。
メモリ切り開く:INTたshmget(key_tのキー、size_tのサイズ、int型shmflag)
- パラメータの説明:
キー:カーネル内の共有メモリを識別し、他のプロセスが同じロゴを通じて同じメモリを開く
サイズ:共有メモリサイズの
shmflg:IPC_CREAT | IPC_EXCL |モードフラグ
戻り値:操作ハンドルの成功のリターンは、メモリ障害を共有-1を返します。
マッピングを確立します。void にshmat(int型のshmidを、constの間隙は、shmaddr、int型shmflg)
パラメータ:
営業ハンドル:shmidを
は、shmaddrによって:最初のアドレスマッピング
動作:shmflg
戻り値:最初のアドレスマッピングの成功を返し、失敗-1
shmdt(shm_start);マッピング関係、最初のアドレスをほのめかしを配置することができます
shmctl(shmidを、IPC_RMID、NULL);削除、共有メモリ
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#define IPC_KEY 0x12345678
#define SHM_SIZE 4096
int main()
{
int shmid=shmget(IPC_KEY,SHM_SIZE,IPC_CREAT|664); //创建一个共享内存
if(shmid<0){
perror("shmget error");
return -1;
}
void *shm_start=shmat(shmid,NULL,0);
if(shm_start==(void*)-1)
{
perror("start error");
return -1;
}
int i=0;
while(1)
{
sprintf(shm_start,"%s-%d\n","good day",i++);//格式化字符串放到buff里面
sleep(1);
}
shmdt(shm_start); //解除映射关系,放入影射首地址就可以
shmctl(shmid,IPC_RMID,NULL); //删除共享内存
return 0;
}
3、メッセージキュー
-
処置:プロセス間のデータブロック伝送
-
本質:カーネルプライオリティキュー、キューにキューノードを配置すること、または通信同じノードを取得することにより、複数のプロセス
-
原則
(1)カーネル内のキュー作成
(2)キューにノードを追加
(3)キューノードから取得
(4)は、メッセージ・キューを削除します -
特性:
(1)メッセージ・キューの同期と相互排他を運ぶ:キューにデータがない場合、受信機は、キューが一杯、そのデータも追加されている障害物である場合、ブロックされる
(2)は、送信データブロックのタイプを有している
(3)データではありません癒着
メッセージキューは現在削除されています
4、セマフォ
- セマフォ:同期や相互排除プロセス間のための
相互排除:一つだけのプロセスが、同時に重要なリソースへのデータの安全な操作にアクセスすることができます-データアクセスのセキュリティの
同期:条件の数から判断するには、重要なリソースを達成するために持っていますデータアクセスの合理性-アクセス順 - エッセンス:+キューを待っているカウンタであるが、唯一の0/1カウンタ二つの状態
- 実現
- 独占:状態のマーカー、重要なリソースの現在の状態によるアクセスの量;状態にアクセスすることができれば、重要なリソースにアクセスする前に、このマークを第1の判定は、この状態はアクセスできないように変更され、データにアクセスするために、アクセスが前に完了します改訂ステータスがアクセスできるようにします。唯一の0/1でカウンターを実装します
- リソースの数をカウントするカウンタを経由して、あなたが重要なリソースを取得したい、リソースがアクセス可能である場合は、最初のカウントを決定し、そうであれば、カウント-1を、動作させるためのリソースを取得するために、何のリソース(すなわちない場合:同期カウント<= 0)、その後、他のプロセス生産データカウント+ 1まで待機し、処理を待っている目を覚まします。決意は、ウェイクアップ機能および待機をカウントすることによって達成され、
- PVセマフォプリミティブ
- P操作:その後、数の決意、-1はリソースが待っされていない場合
- v操作:+1奇数、ウェイクアップ・プロセスが保留キューで待機しています
概要
ここで最初の統合のプロセス間通信の作者は、不十分なフォローアップを追加するために改訂され、また、フォローアップ信号を懸念してくださいまいりますLinux-