[Linux]プロセス間通信(無名パイプ、名前付きパイプ、共有メモリ)

前書き

コミュニケーションの本質は、相互にデータを転送することです。
プロセスは相互にデータを直接転送することはできません。プロセスは独立しています。すべてのデータ操作にはコピーオンライトがあり、中間媒体を介して通信する必要があります。
プロセス間通信の本質:異なるプロセスに同じリソース(メモリ空間)を最初に認識させます。

プロセスコミュニケーション

目的:
データ転送:1つのプロセスがそのデータを別のプロセスに送信する必要があります。
リソース共有:同じリソースが複数のプロセス間で共有されます。
通知イベント:プロセスは、別のプロセスまたはプロセスのグループにメッセージを送信して、何らかのイベントが発生したことを通知する必要があります(プロセスの終了時に親プロセスに通知するなど)。
プロセス制御:一部のプロセスは、別のプロセスの実行を完全に制御したいと考えています。現時点で、制御プロセスは、別のプロセスのすべてのトラップと例外をインターセプトし、時間の経過に伴う状態の変化を知ることができることを望んでいます。

プロセス間通信の開発

1.パイプ2.SystemV
プロセス間通信
3.POSIXプロセス間通信

プロセス間通信の分類

パイプ:
1。無名パイプ
2.名前付きパイプ

System V
IPC1.SystemVメッセージメモリ
2.SystemV共有メモリ
3.SystemVセマフォ

POSIXIPC1
.メッセージキュー
2.共有メモリ
3.セマフォ
4.ミューテックス
5.条件変数
6.読み取り/書き込みロック

パイプライン

ここに画像の説明を挿入

匿名パイプ

血液に関連するプロセスのプロセス間通信を提供します。(親子で一般的)
パイプは一方向にのみデータを通信できます。
したがって、親プロセスと子プロセスは、一方向の通信チャネルを構築する目的を達成するために、不要なファイル記述子を閉じます。
ここに画像の説明を挿入

なぜこれまでに開かなければならないのですか?
読み取りと書き込みを開かない場合、子プロセスによって取得されたファイルは、親プロセスと同じ方法で開かれる必要があり、通信できません。

パイプラインコードをビルドします。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>

int main()
{
    
    
	int pipe_fd[2] = {
    
    0};
	if(pipe(pipe_fd) < 0)
	{
    
    
		perror("pipe");
		return 1;
	}
	printf("%d", %d\n",pipe_fd[0],pipe_fd[1]);
	pid_t id = fork();
	if(id<0)
	{
    
    
		perror("fork");
		return 2;
	}
	else if(id == 0)
	{
    
    
	//关闭读
		close(pipe_fd[0]);

		const char *msg = "hello parent ,i am child";
        int count =5;
		while(count)
		{
    
    
			write(pipe_fd[1],msg,strlen(msg));
			sleep(1);
			count--;
		}
		close(pipe_fd[1]);
		exit(0);
	}
	else
	{
    
    
	//关闭写
		close(pipe_fd[1]);
        
        char buffer[64];
        while(1)
        {
    
    
        	buffer[0] = 0;
        	ssize_t size = read(pipe_fd[0],buffer,sizeof(buffer) - 1);
        	if(size>0)
        	{
    
    
        		buffer[size] = 0;
        		printf("parent get message from child# %s\n",buffer);
        	}
        	else if(size == 0)
        	{
    
    
        		printf("pipe file close,child quit!\n");
        		break;
        	}
        	else
        	{
    
    
        		 //...........
        	}
        }  
        int status = 0;
        if(waitpid(id,&status,0)>0)
        {
    
    
        	printf("child quit,wait success!\n");
        }
        close(pipe_fd[0]);
	}
	return 0;
}

プロセス間同期:
パイプにメッセージがない場合、親プロセス(リーダー)は待機しており、パイプ内のデータの準備ができるまで待機しています(子プロセスが書き込みます)。
パイプの書き込み端がいっぱいの場合。書き込みを続行することはできません。パイプ内の空き領域を待機しています(親プロセスがそれを読み取ります)。
パイプ自体はファイルです。

パイプラインの機能:
1。パイプラインには独自の同期メカニズムがあります。
2.パイプラインは一方向通信です!
3。パイプラインはバイト指向です!
4.パイプは、血縁関係のあるプロセス間の通信のみを保証でき、親子プロセスでよく使用されます。
5.チューブは、データ読み取りのある程度の原子性を保証できます。

プロセスが終了し、一度開いたファイルも閉じられます。パイプもファイルであり、パイプのライフサイクルはプロセスによって異なります。

読んで、書き続けて、無意味です。本質はシステムリソースを浪費することであり、書き込みプロセスはOSによって即座に終了します!
![ここに画像の説明を挿入](https://img-blog.csdnimg.cn/24f1b7304f6c418aa3445425893aae67.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBATGF5bWFu5YWJ772e,size_20,sex_FF

名前付きパイプ

無関係なプロセス間のプロセス間通信は、名前付きパイプと呼ばれます。
匿名パイプ:ファイルの親子共有の特性
名前付きパイプ:ファイルパスは一意であるため、プロセスは同じファイルを見ることができます

共有メモリ

プロセス間通信の本質:異なるプロセスに同じリソースを最初に表示させます!
1.OSは物理メモリスペースの一部を適用します
2.OSはメモリを対応するプロセスの共有領域(スタック間)
にマップします3.OSはマップされた仮想アドレスをユーザーに返すことができます

1.共有メモリを申請します
。2。プロセス1とプロセス2は、それぞれ対応する共有メモリをそれぞれのアドレス空間(共有領域)に接続し
ます。3。両方の当事者が同じリソースを参照します。通常のコミュニケーションは以上です。

オペレーティングシステム内の通信メカニズムを提供する(IPC)ipcモジュール

共有メモリの表示:ipcs -m
すべてのipcリソースは、プロセスではなくカーネルにあります。
共有メモリを削除します:ipcrm -m shmid number

//创建key
key_t k = ftok(PATH_NAME,PROJ_ID);
//申请共享内存
int shmid = shmget(k,SIZE,IPC_CREAT|IPC_EXCL);//共享内存如果不存在,创建;如果存在,出错返回。
//释放共享内存
shmctl(shmid,IPC_RMID,NULL);
//将当前进程和共享内存进行关联
char* start = (char*)shmat(shmid,NULL,0);
//将当前进程和共享内存去关联
shmdt(start);

1.共有メモリのライフサイクルはOSによって異なります
。2。共有メモリは同期および相互排除操作を提供しません。両方の当事者が互いに独立してい
ます。3。共有メモリはすべてのプロセス間通信の中で最速です。

共有メモリサイズ:システムがshmを割り当てる場合、4kbに基づいています。

key:は、ユーザー層によって生成される一意のキー値です。コア機能は「一意性」を区別することであり、IPCリソースの操作には使用できません。
shmid:システムから返されるIPCリソース識別子であり、IPCリソースの操作に使用されます。

類推:
キー、ファイルのiノード番号
shmid、ファイルのfd

信号量

1.プロセスに同じリソース(メモリスペース)を表示させます。このリソースはクリティカルリソースと呼ばれます。
2.プロセス内のすべてのコード。すべてのコードが重要なリソースにアクセスしているわけではなく、一部のみがアクセスしています。データの不整合の問題を引き起こす可能性があるのは、この少量のコードです。(クリティカルセクションコード)
3。データの不整合を回避し、重要なリソースを保護するには、クリティカルセクションコードをある程度保護する必要があります。(この方法は相互排除と呼ばれます)
4。相互排除:スペースの一部には、一度に1つのプロセスのみがアクセスできます。シリアル化された実行(ロック、バイナリセマフォ)
5。ロックおよびロック解除に対応するコードがあります。エッセンス:クリティカルセクションをロックおよびロック解除して、相互排除操作を完了します。

セマフォ:本質的にはカウンターです。(重要なリソースのリソース数を表すために使用されるカウンター)
セマフォの申請:P操作(カウンター減算)
セマフォの解放:V操作(カウンター加算)

PV操作の擬似コード:

P:
begin:
Lock();
	if(count<=0)
	{
    
    
		goto begin;
	}
	else
	{
    
    
		count--;
	}
	Unlock();

//内部访问临界资源。

V:
Lock();
count++;
Unlock();

1.複数のプロセスが同じカウント値で動作することはできません
2.セマフォは重要なリソースを保護する安全性です

セマフォ自体は重要なリソースです。

1.マルチプロセス環境でのセマフォ、セマフォが複数のプロセスで確実に認識されるようにするにはどうすればよいですか?
semget、semctl、ftok()----> Key -----> IPC
2.セマフォのカウンターの値が1の場合、1、0、2
種類の結果、バイナリセマフォ--- ->これは一種の相互排除セマフォです。

おすすめ

転載: blog.csdn.net/qq_46994783/article/details/123373079