[Linux] 프로세스 간 통신(익명 파이프, 명명된 파이프, 공유 메모리)

소개

통신의 본질은 상호적인 데이터를 전송하는 것입니다.
프로세스는 데이터를 서로 직접 전송할 수 없습니다. 프로세스는 독립적입니다. 모든 데이터 작업에는 쓰기 시 복사가 포함되며, 이 작업은 중간 매체를 통해 전달되어야 합니다.
프로세스 간 통신의 본질: 서로 다른 프로세스가 동일한 리소스(메모리 공간)를 먼저 보도록 합니다.

프로세스 커뮤니케이션

목적:
데이터 전송: 한 프로세스는 데이터를 다른 프로세스로 보내야 합니다.
리소스 공유: 동일한 리소스가 여러 프로세스에서 공유됩니다.
알림 이벤트: 프로세스는 일부 이벤트가 발생했음을 알리기 위해 다른 프로세스 또는 프로세스 그룹에 메시지를 보내야 합니다(예: 프로세스가 종료될 때 상위 프로세스에 알림).
프로세스 제어: 일부 프로세스는 다른 프로세스의 실행을 완전히 제어하기를 원합니다. 이때 제어 프로세스는 다른 프로세스의 모든 트랩 및 예외를 가로채고 시간에 따른 상태 변화를 알 수 있기를 바랍니다.

프로세스 간 통신 개발

1. 파이프
2. System V 프로세스 간 통신
3. POSIX 프로세스 간 통신

프로세스 간 통신 분류

파이프:
1. 익명 파이프
2. 명명된 파이프

System V IPC
1.System V 메시지 메모리
2.System V 공유 메모리
3.System V 세마포어

POSIX IPC
1. 메시지 큐
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에 의해 즉시 종료됩니다!
!eg[여기에 이미지 설명 삽입](https://img-blog.csdnimg.cn/24f1b7304f6c418aa3445425893aae67.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50LXplbmhlaQ,shadow_50.

명명된 파이프

관련되지 않은 프로세스 간의 프로세스 간 통신을 명명된 파이프라고 합니다.
익명 파이프: 파일의 부모-자식 공유 특성
명명된 파이프: 파일 경로가 고유하므로 프로세스가 동일한 파일을 볼 수 있습니다.

공유 메모리

프로세스 간 통신의 본질: 서로 다른 프로세스가 동일한 리소스를 먼저 보도록 하십시오!
1. OS는 물리적 메모리 공간의 일부를 적용합니다
. 2. OS는 메모리를 해당 프로세스의 공유 영역(스택 간)
에 매핑합니다. 3. OS는 매핑된 가상 주소를 사용자에게 반환할 수 있습니다.

1. 공유 메모리 신청
2. 프로세스 1과 프로세스 2는 각각 해당 공유 메모리를 자신의 주소 공간(공유 영역)에 연결합니다.
3. 양쪽 당사자는 동일한 리소스를 봅니다! 그것이 정상적인 의사 소통을위한 것입니다!

운영 체제 내부의 통신 메커니즘을 제공하는 (IPC) ipc 모듈

공유 메모리 보기: ipcs -m
모든 ipc 리소스는 프로세스가 아니라 커널에 있습니다.
공유 메모리 삭제: ipcrm -m shmid 번호

//创建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 리소스를 운영하는 데 사용됩니다.

유추:
키, 파일의 inode 번호
shmid, 파일의 fd

신호량

1. 프로세스가 동일한 리소스(메모리 공간)를 보게 하고 이 리소스를 중요 리소스라고 합니다.
2. 프로세스의 모든 코드는 모든 코드가 중요한 리소스에 액세스하는 것이 아니라 일부만 액세스합니다. 데이터 불일치 문제를 일으킬 수 있는 것은 이 작은 양의 코드입니다. (Critical Section code)
3. 데이터 불일치를 방지하고 중요한 자원을 보호하기 위해 Critical Section 코드를 어느 정도 보호해야 합니다. (이 방법을 상호 배제라고 함)
4. 상호 배제: 공간의 일부는 한 번에 하나의 프로세스만 액세스할 수 있습니다. 직렬화된 실행(잠금, 바이너리 세마포어)
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 두 가지 결과, 이진 세마포 --- -> 일종의 상호 배제 의미론입니다.

추천

출처blog.csdn.net/qq_46994783/article/details/123373079