728x90
반응형

1. fork 함수

Process Creation : 부모 함수를 복사해서 새로운 자식 프로세스를 생성한다

Parent & Child : Calling 함수를 parent, 새로운 process를 child라고 한다

Return 값 : fork 함수의 리턴값이 부모와 자식이 다르다

- 자식은 0을 리턴받는다

- 부모는 자식 프로세스의 id를 리턴받는다.

- 에러가 발생했을시 부모에게 음수를 전달한다.

부모와 자식은 concurrent하게 실행된다.

자식 프로세스는 부모 프로세스 코드를 그대로 실행하고 부모 코드를 자식도 가진다.

자식 프로세스는 fork 함수의 리턴값을 받으면서 fork 함수 아랫줄 라인을 실행하게 된다.

부모 프로세스는 그대로 실행하고 이것과 별개로 자식 프로세스는 fork()에서 0을 리턴받고 fork함수의 아래줄을 실행한다.

- fork를 위해서는 #include <unistd.h> 포함해주자.

 

2. fork() 함수의 특징

fork 함수는 부모의 이미지를 복사해서 새로운 process를 만든다.

child 함수는 부모의 attributes, 예를 들어 environment(환경 변수)와 privileges(권한 정보)를 물려받는다.

open files와 devices같은 부모의 resources도 물려받는다.

fork함수로 만들어진 자식프로세스와 부모 프로세스 관계

- PID와 PPID는 다르다 (상식적으로 일단 다른 프로세스니까)

- 모든 data는 copy된다

- 같은 코드를 사용한다

- 같은 지점부터 실행한다.

- 서로 다른 return 값을 가진다(fork()이후)

 

3. Parent 속성과 resources : 모든 속성과 resources들이 자식에게 물려지는것은 아니다.

Process ID : 자식은 새로운 process ID를 가진다.

CPU Usage (프로세스가 CPU를 얼마나 사용하는지에 대한 정보)

- 자식의 CPU usage 시간은 0으로 reset된다.

Locks and alarm (lock 정보를 물려주면 2개의 process가 둘 다 동시에 access 하기 때문에 불가능하다)

- Lock : 프로세스간 동기화 관련된 부분, resource를 동시에 access하게 되면 conflict 문제가 발생하므로 이를 해결하기 위해 OS에게 lock을 요청한다.

- 자식은 부모가 가지고 있는 lock은 가지지 않는다.

- 만약 부모가 alarm을 가진다면 child는 부모 알람이 끝나도 자식에게 알려지지 않는다

Pending signals : 어떤 event에 대한 통지수단

- 자식은 pending signal없이 시작한다. 부모가 signal의 pending을 fork할때 가지고 있다고 할지라도.

 

4. Parent Attributes and  Resources

자식 프로세스는 분리된 entity로서 processor time을 위해 경쟁한다.

유저가 CPU타임을 더 얻기 위해 많은 process를 만들면 된다.

 

5. fork의 장단점

장점 : child는 parent의 모든 데이타를 상속받는다. process간의 통신은 IPC라는 것을 통해 하는데 child와 parent는 IPC 사용이 필요없어 통신에 장점이 있다.

단점 : 전혀 다른 코드 실행을 위해서는 제한이 있다.

-> 그래서 return값이 다르다는 점을 이용해서 concurrent하게 일부 다른 부분 실행하게 만들 수 있다.

자식이 fork되면 부모가 먼저 실행될까 자식이 먼저 실행될까?

- 대부분 부모이지만 OS의 스케쥴링 시스템에 의해서 무슨 일이 벌어질지는 모른다. 

 

Example 1>

#include <stdio.h>
#include <unistd.h>

int main(void)
{
    int x;
    x = 0;

    fork();

    x = 1;
    printf("I am process %ld and my x is %d\n", (long)getpid(), x);
}

다음과 같은 코드는 fork()함수를 통해 자식을 생성하고 부모 코드에서 선언해둔 x의 값과 자식 프로세스에서의 x의 값이 어떻게 다른지 확인할 수 있다. 자식 프로세스에서도 부모와 동일한 코드를 가지게 되므로 x=0이고 fork()이후에 x=1로 바껴서 출력된다.

I am process 5731 and my x is 1
I am process 5711 and my x is 1

 

자식 프로세스와 부모 프로세스가 다르게 동작하게 하고 싶으면 어떤 방법을 통해서 할 수 있을까? 

fork()함수에서 return 값이 다르다는 것을 이용하면 된다. 자식 프로세스는 fork()함수에서 0을 리턴받지만 부모 프로세스는 새소 생성된 자식 Process ID를 return 값으로 전달받는다.

Ex 2>

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main(void)
{
    pid_t childpid;

    childpid = fork();
    if (childpid == -1)
    {
        perror("Faild to work");
    }
    if (childpid == 0)
    {
        printf("I am child %ld\n", (long)getpid());
    }
    else
    {
        printf("I am parent %ld\n", (long)getpid());
    }
    return 0;
}

if 함수를 통해서 3가지로 분기하였다. childpid가 -1을 받을때는 perror를 출력, 0일때는 자식 프로세스 실행, else일 때 부모 프로세스를 실행시켰다. 

I am child 6495
I am parent 6472

 

Ex 3> 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//argc개의 process를 chain형태로 실행시키기 위함.
int main(int argc, char *argv[])
{
    pid_t childpid = 0;
    int i, n;

    if (argc != 2)
    { //check for valid number of command-line arguments
        fprintf(stderr, "Usage: %s processes\n", argv[0]);
        return 1;
    }
    n = atoi(argv[1]); //atoi함수는 String을 Int로 변환해준다.
    for (i = 1; i < n; i++)
    {
        if (childpid = fork()) //부모 프로세스는 fork()한 다음 break로 빠져나감. 부모 프로세스는 return 값이 0보다 클것이기 때문에 0보다크면 true
        {
            break;
        }
        // 자식 프로세스는 zero value를 return받으므로 다음 loop iteration에서 부모가 된다.
        // 에러가 생기면 fork는 -1을 리턴하고 loop빠져나간다.
    }
    fprintf(stderr, "i:%d process ID:%ld parent ID:%ld childID:%ld\n", i, (long)getpid(), (long)getppid(), (long)childpid);
    return 0;
}

위의 함수는 chain형태로 하나의 부모프로세스에서 그 부모 프로세스는 break되고 자식프로세스가 다시 부모프로세스가 되어 자식 프로세스를 생성하는 프로그램이다.

 

Ex 4>

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

int main(int argc, char *argv[])
{
    pid_t childpid = 0;
    int i, n;

    if (argc != 2)
    {
        fprintf(stderr, "Usage:%s processes\n", argv[0]);
        return 1;
    }
    n = atoi(argv[1]);
    for (i = 1; i < n; i++)
    {
        if ((childpid = fork()) <= 0) //부모가 아닌 경우 break되므로 자식은 모두 break되고 부모 하나만 남는다.
        {
            break;
        }
    }
    fprintf(stderr, "i:%d processID:%ld parentID:%ld childID:%ld\n", i, (long)getpid(), (long)getppid(), (long)childpid);
    return 0;
}

위 프로그램은 하나의 부모 프로세스에서 계속 분기하여 자식프로세스를 만든다. 물론 자식프로세스도 진행되며 부모프로세스가 되어 자식 프로세스를 만들게 된다.

 

6. wait() function

부모 프로세스는 자식 프로세스가 종료되었는지 여부를 체크할 필요가 있다. wait함수를 사용하면 부모 자식의 종료시점이 서로 동기화되는 방식으로 작동한다.

- wait function은 자식의 상태가 변경되었을 경우(일반적인 경우는 종료) 부모 프로세스(caller)가 대기(suspend execution)하게 한다. 

wait function은 부모 프로세스에게 다음을 허용한다.

1) 자식프로세스가 종료될때까지 기다림

2) 자식프로세스의 상태 전달받음

3) 자식 프로세스가 종료하면서 return이 있다면 넘겨받을 수 있다.

 

7. wait and waitpid function

1) #include <sys/wait.h> 사용

2) pid_t wait(int *stat_loc);

wait는 종료한 자식 processID를 반환한다.

- stat_loc으로 종료 상태 정보도 return 가능

- 비정상종료일때 몇번 signal을 받아 종료되었는지도 확인가능

3) pid_t waitpid(pid_t pid, int *stat_loc, int options);

- 첫번째 파라미터를 0으로 주게되면 자식 process 중 부모 process와 같은 process 그룹 중 하나를 선택함

- 특정 자식 프로세스나 특정 프로세스 그룹의 자식을 wait 할 수 있음

- option은 non-blocking모드로 작동할 수도 있다 (WHOHANG으로 마지막 파라미터를 뒀을 경우)

- error가 발생하면 -1이나 errno전달받음

wait나 waitpid는 wait가 완료될때까지 실행이 suspend된다. ==>blocking 버전 함수

non-blocking모드는 한번 함수가 task완료할 수 있는지 check해보는 의미이다. 

자식 프로세스가 끝났나? 한번 체크해보고 종료된 자식 process있으면 종료된 자식process 리턴한다.

 

ex> waiting for all children

 

 

 

728x90
반응형

'CS > 시스템 프로그래밍' 카테고리의 다른 글

Times and Timers  (0) 2021.11.16
UNIX Special Files  (0) 2021.11.03
Files and Directories  (0) 2021.10.15
UNIX I/O  (0) 2021.10.15
Process  (0) 2021.10.03

+ Recent posts