142-プロセス間通信(セマフォ)

重要なリソース:同時に1つのプロセスまたはスレッドからのみアクセスが許可されるリソース
重要な領域
:ショッピングモールの試着室、交差点の
同期などの重要なリソースにアクセスするコードセグメント:プログラム実行の正確性を確保するための制御、セマフォを使用する

セマフォは特別な変数であり、通常は正の値を取ります。その値は、アクセスが許可されているリソースの数を表します。リソースを取得するときは、セマフォの値を1つアトミックに減らす必要があります。この操作はP操作と呼ばれます
セマフォ値が0の場合、使用可能なリソースがなく、P操作がブロックされることを意味します。
リソースを解放するときは、セマフォの値に1をアトミックに追加する必要があります。この操作はV操作と呼ばれます
セマフォは主にプロセスを同期するために使用されます。セマフォの値が0、1のみである場合、それはバイナリセマフォと呼ばれます。
セマフォの値が1より大きい場合、それはカウントセマフォと呼ばれます。たとえば、3人用の試着室が3つあります。4人目は、
PV操作がリソースの取得と解放の
原子性保証通過するのを待つ必要があり、問題はありません。

例:
nは列車のチケットの残りの数を表します。
全員がチケットを購入し、n-1
2人
がチケットを購入します。チケットの購入は並行プロセスであるため、実際にはn-2である必要があり
ます。 nの値を1減らすために1つ必要です。プロセス中に、n = 5はプロセッサに読み取り、完了していない1だけデクリメントする準備をします。同時に、別の訪問者もn = 5を読み取ります。プロセッサは1をデクリメントする準備をし、最後の2つのプロセスは4を
n = 4に書き戻します。
ここに画像の説明を挿入

この結果4は明らかに問題がある
ため、nを同時に制御するのではなく、制御
する必要があります。この問題を解決するには、アトミック操作のセマフォを使用する必要があります
。PV操作を通じて0,1

例2:
プリンタへのアクセス
ここに画像の説明を挿入
はセマフォで制御する必要があります。
ここに画像の説明を挿入
最初に、AはP演算を実行してセマフォの値(1)を取得し、1を減算すると、0
になります。Vが実行される前に、Aが使用されています。このとき、Bアクセス、p操作、セマフォ0の検出、ブロック

同じ端末で同時にviac
ここに画像の説明を挿入
vi bc
ここに画像の説明を挿入

ここに画像の説明を挿入

次に、セマフォを使用して次のように問題を解決します。

操作セマフォのインターフェース導入:

#include <sys/sem.h>
#include <sys/types.h>
#include <sys/ipc.h>
/*
semget()创建或者获取已存在的信号量
semget()成功返回信号量的 ID, 失败返回-1
key:两个进程使用相同的 key 值,就可以使用同一个信号量
nsems:内核维护的是一个信号量集,在新建信号量时,其指定信号量集中信号
量的个数
semflg 可选: IPC_CREAT IPC_EXCL
*/

int semget(key_t key, int nsems, int semflg);//创建,获取信号量

/*
semop()对信号量进行改变,做 P 操作或者 V 操作
semop()成功返回 0,失败返回-1
struct sembuf
{
unsigned short sem_num; //指定信号量集中的信号量下标
short sem_op; //其值为-1,代表 P 操作,其值为 1,代表 V 操作
short sem_flg; //SEM_UNDO
};
*/

int semop(int semid, struct sembuf *sops, unsigned nsops);//初始化

/*
semctl()控制信号量
semctl()成功返回 0,失败返回-1
cmd 选项: SETVAL IPC_RMID

union semun
{
int val;
struct semid_ds *buf;
unsigned short *array
struct seminfo *_buf;
}; */

int semctl(int semid, int semnum, int cmd, ...);

ここに画像の説明を挿入
セマフォをカプセル化するためのインターフェース:
ここに画像の説明を挿入

vi sem.h.

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

union semun{
    
    
	int val;//初始值 
};

void sem_init();//创建/或者已存在的信号量
void sem_p();//p 减一
void sem_v();//v 加一
void sem_destroy();//销毁

あなたsem.c.

#include "sem.h"

static int semid = -1;

void sem_init()//创建/或者已存在的信号量
{
    
    
	semid = semget((key_t)1234,1,IPC_CREAT|IPC_EXCL|0600);//约定都使用这个key_t值,1个信号量,全新创建
	if ( semid == -1 )//已存在
	{
    
    
		semid = semget((key_t)1234,1,0600);//存在就直接获取
	}
	else
	{
    
    
		union semun a;

		a.val = 1;//信号量的初始值
		if ( semctl(semid,0,SETVAL,a) == -1 )//下标为0,初始化失败
		{
    
    
			perror("semctl error");
		}
	}
}

void sem_p()//p 减一
{
    
    
	struct sembuf buf;
	buf.sem_num = 0;//成员下标
	buf.sem_op = -1;//p
	buf.sem_flg = SEM_UNDO;

	if ( semop(semid,&buf,1) == -1 )
	{
    
    
		perror("semop p error");
	}
}

void sem_v()//v 加一
{
    
    
	struct sembuf buf;
	buf.sem_num = 0;//成员下标
	buf.sem_op = 1;//v
	buf.sem_flg = SEM_UNDO;

	if ( semop(semid,&buf,1) == -1 )
	{
    
    
		perror("semop v error");
	}
}

void sem_destroy()//销毁
{
    
    
	if ( semctl(semid,0,IPC_RMID) == -1 )
	{
    
    
		perror("semctl del error");
	}
}

vi ac

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>

int main()
{
    
    
	sem_init();//初始化1
	int i = 0;
	for( ;i < 10; i++ )
	{
    
    
		sem_p();//如果检测到1,通过,减1
		printf("a");
		fflush(stdout);
		int n = rand() % 3;
		sleep(n);
		printf("a");
		fflush(stdout);
		sem_v();

		n = rand() % 3;
		sleep(n);
	}
}

ここに画像の説明を挿入
vi bc

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>

int main()
{
    
    
	sem_init();
	int i = 0;
	for( ;i < 10; i++ )
	{
    
    
		sem_p();
		printf("b");
		fflush(stdout);
		int n = rand() % 3;
		sleep(n);
		printf("b");
		fflush(stdout);
		sem_v();

		n = rand() % 3;
		sleep(n);
	}
}

ここに画像の説明を挿入
コンパイルして実行する
ここに画像の説明を挿入
ここに画像の説明を挿入
このセマフォは、カーネルに通知することによって作成され、カーネルは
それを維持します。終了した後も、カーネルは維持されて
おり、セマフォが使用されている可能性があります。

一度だけ削除できます

ここに画像の説明を挿入
使用後は削除する必要があります。削除しないと、1か0(前回)かわかりません
コマンドを使用して削除してください。次の質問を見てください。
ここに画像の説明を挿入
ここに画像の説明を挿入

3つのプロセスa、b、およびcは、それぞれ「A」、「B」、および「C」を入力し、出力結果は「ABCABCABC ...」である必要があります。

3つのセマフォのうち最初のセマフォは1に初期化され、最後の2つは0に初期化されます。ps1初めて通過し、ps2ps3は通過
ここに画像の説明を挿入
ません
ここに画像の説明を挿入
ここに画像の説明を挿入ここに画像の説明を挿入

ここに画像の説明を挿入ここに画像の説明を挿入
vi ac
ここに画像の説明を挿入

vi bc
ここに画像の説明を挿入

vi cc
ここに画像の説明を挿入
run
ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/LINZEYU666/article/details/112899094