Skip to content
ChoYG edited this page Aug 1, 2016 · 2 revisions

리눅스 환경에서 멀티 프로세스로 돌리기

내가 주로 쓰던 RTOS 환경에서는 쓰래드(테스크) 하나는 무한반복문 이었고, 스케줄러는 우선순위에 의해 어떤 테스크를 실행시킬지 결정하는 비선점형 방식 이었다.

그런데 리눅스 환경에서 사용하는 fork라는 녀석의 동작은 내가 생각하던 멀티 프로세스 프로그래밍 하고 조금 느낌이 달랐다. 하나의 프로세스가 돌다가, fork라는 함수를 만날 경우 슬라임마냥 분열한다. 이때 원래 돌던 프로세스는 부모 프로세스가 되고, 분열된 프로세스는 분열전 부모 프로세스의 기억을 가지고 있는 자식프로세스가 된다(징그럽;).

fork의 리턴값은 다음과 같다.

  • 자식 프로세스는 0의 리턴값을 받는다.
  • 부모 프로세스는 자식 프로세스의 pid(프로세스 ID)를 받는다.
  • 분열이 잘 안되면 -1

fork1

#include <stdio.h>

int main(void)
{
	int pid;
	printf("[%d] process start \n", getpid());

	pid = fork();
	printf("[%d] process : return value %d \n", getpid(), pid);

	return 0;
}

실행하면 대충 다음과 같이 나온다.

[4044] process start 
[4044] process : return value 4045 
[4045] process : return value 0 

첫번째 printf 문에서 현제 돌고 있는 프로세스의 pid 값을 보여준다.
두번째 printf 문은 부모, 자식이 나뉘어져서, 부모쪽은 자식쪽(4045) pid 값을 fork의 리턴값으로 받는 것을 볼 수 있다. 분열된 자식은 0의 리턴값을 받는다.

fork2

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
	int pid;

	pid = fork();

	if(pid == 0)//자식 프로세스
	{
		printf("[child] : Hello, world pid = %d \n", getpid());
	}
	else // 부모 프로세스
	{
		printf("[parent] : Hello, world pid = %d \n", getpid());
	}

	return 0;
}
[parent] : Hello, world pid = 5243 
[child] : Hello, world pid = 5244 

이번엔 fork의 리턴값을 응용하여, 부모와 자식 프로세스가 서로 다른 일을 하게끔 만드는 예제다. if 문을 이용하여 fork의 리턴값이 0일땐 자식, 다른값(자식 pid) 일땐 부모 프로세스의 일로 나눴다.

fork3

#include <stdlib.h>
#include <stdio.h>

int main(void)
{
	int pid1, pid2;
	
	pid1 = fork();

	if(pid1 == 0)
	{
		printf("[child 1] Hello, world! pid = %d\n", getpid());
		exit(0);
	}

	pid2 = fork();
	
	if(pid2 == 0)
	{
		printf("[child 2] Hello, world! pid = %d\n", getpid());
		exit(0);
	}

	return 0;
}

이번엔 fork를 두번 사용하였다.

[child 1] Hello, world! pid = 5368
[child 2] Hello, world! pid = 5369   

첫번째 fork 후 첫번째 자식 프로세스가 생성되어 printf 문 출력후 종료한다.
두번째 fork 후 두번째 자식 프로세스가 생성되어 printf 문 출력후 종료한다.
이때 둘다 부모 프로세스에서 분열된 프로세스이다.

forkwait

이번엔 부모 자식간의 선형화(이렇게 표현해도 되는지는 모르겠다.)를 위해 wait 라는 함수를 사용해 본다.
부모, 자식 프로세스로 나눌떄 만약 부모 프로세스가 먼저 종료될 경우, 자식 프로세스는 고아 프로세스가 된다고 한다(히익;). 때문에 왠만하면 자식 프로세스 부터 죽이고 부모 프로세스를 죽이는게 좋다고 한다. wait는 자식 프로세스가 죽을때까지 기다리는 함수라고 보면 된다.

wait 의 경우 가장 먼저 죽은 자식 프로세스 순으로 진행된다.

예제를 보는게 낫다.

#include <stdio.h>
#include <stdlib.h>
#include <wait.h>

int main(void)
{
	int pid, child, status;

	printf("[%d] parent process start\n", getpid());

	pid = fork();

	if(pid == 0)
	{
		printf("[%d] child process start\n", getpid());
		exit(1);
	}

	child = wait(&status);//1 -> 1 0000 0000 == 256
	printf("[%d] child process %d exit\n", getpid(), child);
	printf("\t exit code %d\n", status >> 8);
}
[5519] parent process start
[5520] child process start
[5519] child process 5520 exit
	 exit code 1

fork 후 자식 프로세스 구간에서 exit(1)로 exit라는 함수에 1을 넣어주고 종료했다. 넣어준 1은 wait 함수에서 인자 status로 전달하는데, 전달하는 과정에서 조금 이상하게 전달된다. 1을 전달하면 1의 8승(1을 왼쪽으로 8번 쉬프트)의 값이 전달된다. 1주면 256의 값이 status에 저장된다.

만약 마지막

printf("\t exit code %d\n", status >> 8);

에서 >> 8 을 해주지 않을 경우 256이 출력 될 것이다.

wait의 반환값은 종료된 자식 프로세스 이며, 잘 종료가 안되거나 하면 -1이 반환된다.

wait와 waitpid

wait(상태값 저장할 버퍼 포인터)

임의로 자식 프로세스중 아무거나 죽으면 반환되는 함수.
예로 status라는 버퍼에 임의로 죽은 자식의 값을 저장한다면

int status;

wait(&status);

와 같이 사용하면 된다.

waitpid(pid값, 상태값 저장할 버퍼 포인터, 옵션)

pid값

  • 0 : 현제 자신의 그룹과 같은 자식 프로세스를 기다린다.
  • -1 : 임의로 아무 자식 프로세스나 죽는지 기다린다.
  • 양수(pid값) : 인자로 넣어준 pid 를 가진 자식 프로세스가 죽는지 기다린다.

옵션

  • 0 : 자식 프로세스가 죽을때까지 기다린다.
  • WNOHANG : 자식 프로세스가 죽을때까지 기다리지 않는다.
    자식 프로세스가 살아있으면 0을 반환한다.
    자식 프로세스가 죽었으면 자식 프로세스의 pid 값을 반환한다.

Clone this wiki locally