9. 프로세스 제어

9.1 프로세스 생성

1. 프로세스 생성

  • fork() 시스템 호출
    - 부모 프로세스를 똑같이 복제하여 새로운 자식 프로세스를 생성(자기복제)

ex) fork1.c

#include <stdio.h>
#include <unistd.h>
/* 자식 프로세스를 생성한다. */
int main()
{ 
int pid;
printf("[%d] 프로세스 시작 \n", getpid());
pid = fork();
printf("[%d] 프로세스 : 리턴값 %d\n", getpid(), pid);
}

[31563] 프로세스 시작
[31563] 프로세스 : 리턴값 31564
[31564] 프로세스 : 리턴값 0

2. 부모 프로세스와 자식 프로세스 구분

  • fork() 호출 후에 리턴값이 다르므로 이 리턴값을 이용해 부모프로세스와 자식프로세스를 구별하고 서로 다른 일을 하도록 할 수 있다.

pid = fork();
if(pid==0)
{ 자식프로세스의 실행코드 }

else
{ 부모프로세스의 실행코드 }

ex) fork2.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
/* 부모 프로세스가 자식 프로세스를 생성하고 서로 다른 메시지를 프린트 */

int main()
{
	int pid;
	pid = fork();

	if(pid==0)
	{
		printf("[CHILD] : HELLO~ pid = %d\n",getpid());
	}
	else
	{
		printf("[PARENT] : HELLO~ pid= %d\n",getpid());
	}
}

ex) fork3.c

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

/* 부모 프로세스가 두 개의 자식 프로세스를 생성한다. */

int main() 
{
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);

}

}

3. 프로세스 기다리기 : wait()

  • 자식 프로세스 중의 하나가 끝날 때까지 기다린다.
    - 끝난 자식 프로세스의 종료 코드가 status에 저장되며,
    • 끝난 자식 프로세스의 번호를 리턴
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
int main()
{
	int pid, child, status;
	printf("[%d] 부모 프로세스 시작 \n", getpid());	

	pid = fork();

	if (pid == 0) {
		printf("[%d] 자식 프로세스 시작 \n", getpid( ));
		exit(1);
	}

	child = wait(&status); // 자식 프로세스가 끝나기를 기다린다.
	printf("[%d] 자식 프로세스 %d 종료 \n", getpid(), child);
	printf("\t종료 코드 %d\n", status>>8);

}

[23184] 부모 프로세스 시작
[23185] 자식 프로세스 시작
[23184] 자식 프로세스 23185 종료
종료 코드 1

4. fork() 후에 파일 공유

  • 자식은 부모의 fd 테이블을 복사한다.
    - 부모와 자식이 같은 파일 디스크립터를 공유
    • 같은 파일 오프셋을 공유
    • 부모와 자식으로부터 출력이 서로 섞이게됨
  • 자식에게 상속되지 않는 성질
    1. fork()의 반환값
    2. 프로세스 ID
    3. 파일 잠금
    4. 설정된 알람과 시그널

9.2 프로그램 실행

프로그램 실행

  • fork() 이후 자식프로세스는 부모 프로세스와 똑같은 코드 실행

  • 자식 프로세스에세 새 프로그램 실행
    : __exec() 시스템 호출 사용
    : 프로세스 내의 프로그램을 새 프로그램으로 대치

  • 보통 fork() 후에 exec()

프로그램 실행 : exec()

  • 프로세스가 exec() 호출
    : 그 프로새스 내의 프로그램은 완전히 새로운 프로그램으로 대치 ( 자기대치 )
    : 새 프로그램의 main()부터 실행이 시작된다.

  • exec() 호출이 성공하면 리턴할 곳이 없어진다.
  • 성공한 exec() 호출은 절대 리턴하지 않는다

  • 보통 fork() 후에 exec()를 호출하는데
    : 새로 실행할 프로그램에 대한 정보를 arguments로 전달한다.
  • exec() 호출이 성공하면

자식 프로세스는 새로운 프로그램을 실행하게 되고 부모는 계속해서 다음 코드를 실행하게 된다.t


if ((pid = fork()) == 0 ){
exec( arguments );
exit(1);
}
// 부모 계속 실행

ex) execute1.c


#include <stdio.h>
/* 자식 프로세스를 생성하여 echo 명령어를 실행한다. */

int main( ) 
{

printf("부모 프로세스 시작\n");

// 자식프로세스 생성 
if (fork( ) == 0) {
execl("/bin/echo", "echo", "hello", NULL);
fprintf(stderr,"첫 번째 실패"); 
exit(1);
}
printf("부모 프로세스 끝\n");

ex2) execute2.c

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

/* 자식프로세스를 생성하여 echo 명령어를 실행한다. */

int main()
{
	printf("부모 프로세스 시작\n");
	if(fork()==0)
	{
		execl("/bin/echo","echo","hello",NULL);
		fprintf(stderr,"첫 번째 실패");
		exit(1);
	}
	
	if(fork()==0)
	{
		execl("/bin/date","date",NULL);
		fprintf(stderr,"두 번째 실패");
		exit(2);
	}
	
	if (fork( ) == 0) 
	{
		execl("/bin/ls","ls", "-l", NULL);
		fprintf(stderr,"세 번째 실패"); 
		exit(3);
	}
	
	printf("부모 프로세스 끝\n");
	
}

ex) execute3.c

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

/* 자식프로세스를 생성하여 echo 명령어를 실행한다. */

int main(int argc, char* argv[])
{
	int child,pid,status;
	
	pid = fork();
	
	// 자식프로세스 
	if(pid==0) 
	{
		execv(argv[1],&argv[1]);
		fprintf(stderr,"%s:실행 불가\n",argv[1]);
		
	}
	// 부모 프로세스 
	else
	{
		child = wait(&status);
		printf("[%d] 자식 프로세스 %d 종료\n",getpid(),pid);
		printf("\t종료 코드 %d\n",status>>8);
	}
	
}

system()

  • 자식프로세스를 생성하고 /bin/sh로 지정된 명령어를 실행시킨다
    ex) system("date > file);

  • system() 함수 구현
    : fork(), exec(), waitpid() 시스템 호출이용

  • 반환값
    명령어의 종료코드 : 성공
    127 : exec() 실패
    -1 : 다른오류

  • system() 구현

#include <sys/types.h> /* system.c */
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h>

int system(const char *cmdstring) 
{
	pid_t pid; int status;
	
	if (cmdstring == NULL) /* 명령어가 NULL인 경우 */
	return(1); 
	
	if ( (pid = fork()) < 0)
	{
		status = -1; /* /* 프로세스 생성 실패 */
	} 
	
	else if (pid == 0) 
	{ 	/* 자식 */
  		execl("/bin/sh", "sh", "-c", cmdstring, (char *) 0);
		_exit(127); /* execl 실패 */
	} 
	
	else 
	{   /* 부모 */
		while (waitpid(pid, &status, 0) < 0)
			if (errno != EINTR) {
			status = -1; /* waitpid()로부터 EINTR외의 오류 */
			break;
			}
		
	}
	
	return(status);
	
}

좋은 웹페이지 즐겨찾기