IPC 프로세스 간 커뮤니케이션

Nam Eun-Ji·2020년 11월 19일
0

프로세스 간에는 커뮤니케이션을 할 수 있는 직접적인 방법은 없다.
프로세스 간 통신 기법 : 특별한 IPC(InterProcess Communication) 기법을 사용하여 진행.



왜 필요할까?

프로세스들이 서로의 공간을 쉽게 접근할 수 있다면?

  • 프로세스 데이터/코드가 바뀔 수 있어 위험하기 때문에 프로세스는 다른 프로세스의 공간을 접근할 수 없게끔 하였다.

성능을 높이기 위해 여러 프로세스를 만들어서 동시 실행할 때

  • 이 때 프로세스간 상태 확인 및 데이터 송수신 필요.



다양한 IPC 기법

대부분의 IPC기법은 결국 커널공간을 활용하는 것임 : 커널공간은 공유하기 때문.
2번부터는 모두 커널 공간을 사용하는 것임 : 저장매체보다는 액세스하는 시간이 짧고 프로세스간 공유가 쉬움.
시그널과 소켓은 IPC기법으로 나온 것은 아니지만 기능을 이용하여 IPC로 사용가능하다.

  1. file 사용 : 실시간 ↓ 저장매체 ↓
  2. Message Queue
  3. Shared Memory
  4. Pipe
  5. Signal
  6. Semaphore
  7. Socket



Message Queue

  • 큐이므로, 기본은 FIFO 정책으로 데이터 전송.
  • 메시지큐는 커널에서 전역적으로 관리되며(이를테면 커널 전역변수형태로), 모든 프로세스에서 접근가능하도록 되어있으므로, 하나의 메시지큐 서버가 커널에 요청해서 메시지큐를 작성하게 되면, 메시지큐의 접근자(식별자)를 아는 모든 프로세서는 동일한 메시지큐에 접근함으로써, 데이타를 공유할수 있게 된다.



Shared Memory

  • 노골적으로 커널공간에 메모리 공간을 만들고, 해당 공간을 변수처럼 쓰는 방식
  • Message Queue처럼 FIFO 방식이 아니라, 해당 메모리 주소를 마치 변수처럼 접근하는 방식
  • 공유메모리 key를 가지고, 여러 프로세스가 접근 가능

코드 예제

  1. 공유 메모리 생성 및 공유 메모리 주소 얻기
shmid = shmget((key_t)1234, SIZE, IPC_CREAT|0666))
shmaddr = shmat(shmid, (void *)0, 0)
  1. 공유 메모리에 쓰기
strcpy((char *)shmaddr, "Linux Programming")
  1. 공유 메모리에서 읽기
printf("%s", (char *)shmaddr)



Pipe

  • 기본 파이프는 단방향 통신
  • fork()로 자식 프로세스 만들었을 때, 부모와 자식간의 통신
    • fork()를 하게 되면 새로운 프로세스가 생기는데, 기존 프로세스의 코드, 스택, 데이타 등을 완벽히 복사하게 된다. 그러면 PC(program counter)가 부모, 자식의 fork() 다음 코드를 그대로 가르킨다.
    • 부모 프로세스는 pid에 실제 프로세스 ID가 들어감(pid > 0)
    • 자식 프로세스는 pid가 0이 들어감(pid == 0)
// 파이프 코드 예제
char* msg = "Hello Child Process!";
int main(){
	char buf[255];
	int fd[2], pid, nbytes;
	if(pipe(fd) < 0){   // pipe(fd)로 파이프 생성
		exit(1);
	}
	pid = fork();  // 이 함수 실행 다음 코드부터 부모/자식 프로세스로 나뉘어짐
	if(pid > 0){   // 부모 프로세스는 pid에 실제 프로세스 ID가 들어감
		write(fd[1], msg, MSGSIZE);   // fd[1]에 씀
		exit(0);
	} else {    // 자식 프로세스는 pidrk 0이 들어감 
		nbytes = read(fd[0], buf, MSGSIZE);   // fd[0]으로 읽음
		printf("%d %s\n", nbytes, buf);
		exit(0);
	}
	return 0;
}

// 부모프로세스에서 write한 것을 자식프로세스에서 read할 수 있다는 것이 핵심. 즉 통신한다는 것.
// write(fd[1]) -> read(fd[0])

위 그림을 보면 부모프로세스에서 read는 할 수 없고, 자식프로세스에서 write를 할 수 없기 때문에 단방향통신이라고 불리는 것이다.




Signal

  • 유닉스에서 30년 이상 사용된 전통적인 기법
  • 커널 또는 프로세스에서 다른 프로세스에 어떤 이벤트가 발생되었는지를 알려주는 기법
  • 프로세스 관련 코드에 관련 시그널 핸들러를 등록해서, 해당 시그널 처리 실행
    • 시그널 무시
    • 시그널 블록(블록을 푸는 순간, 프로세스에 해당 시그널 전달)
    • 등록된 시그널 핸들러로 특정 동작 수행
    • 등록된 시그널 핸들러가 없다면, 커널에서 기본 동작 수행
  • 시그널은 이미 운영체제에서 정의되어 있는 이벤트이다.
    • 주요 시그널 : 기본 동작
      • SIGKILL : 프로세스를 죽임(슈퍼관리자가 사용하는 시그널로, 프로세스는 어떤 경우든 죽도록 되어 있음)
      • SIGALARM : 알람 발생
      • SIGSTP : 프로세스를 멈춤(ctrl + z)
      • SIGCONT : 멈춰진 프로세스를 실행
      • SIGINT : 프로세스에 인터럽트를 보내서 프로세스를 죽임(ctrl + c)
      • SIGSEGV : 프로세스가 다른 메모리영역을 침범
    • 시그널 종류를 보려면 터미널에서 kill -l 이라고 치면 나온다.



Semaphore

세마포어는 프로세스 사이의 동기를 맞추는 기능을 제공한다. 프로세스간에 공유 영역에 대한 접근 순서를 정해주어 공유 메모리가 손상되는 현상을 막아준다.




Socket

  • 소켓은 네트워크 통신을 위한 기술
  • 기본적으로는 클라이어트와 서버 등 두개의 다른 컴퓨터 간의 네트워크 기반 통신을 위한 기술
  • 소켓을 하나의 컴퓨터 안에서, 두개의 프로세스간에 통신 기법으로 사용 가능
profile
한 줄 소개가 자연스러워지는 그날까지

0개의 댓글