학교 강의를 복습하는 차원에서 작성하는 글입니다.
학부생 수준의 글이므로, 오류가 있을 수 있는 점 양해바람니다.
Process
Process는 실행 중인 상태의 프로그램을 말하며,
동일한 프로그램으로 여러 개의 프로세스를 만들 수 있고. 각 프로세스는 프로그램의 Instance(메모리에 할당된 객체)라고 볼 수 있다.
*프로그램은 명령어 코드를 담고 있는 파일을 말한다.
* 프로그램 on DISK => (프로그램 실행) => Process on Memory(RAM)
사용자는 Shell Prompt 상에서 Program을 지정해 실행해 프로세스를 생성하거나
실행 중인 User Process가 Program을 실행하는 방식으로 프로세스를 생성한다.
두 가지 방법은 사실 동일한데. Shell Prompt를 보여주고 있는 Shell Process가 이미 실행 중인 프로세스이기 때문이다.
=> shell도 프로그램이므로 터미널을 키면 shell이 이미 들어가 있고. 타이핑을 치면 해당 프로그램이 실행 된다.(커널이 제일 먼저다.)
=> shell prompt에서 유저가 타이핑 해서 프로그램을 실행 vs 프로세스에서 다른 프로세스를 함수 호출을 통해 실행하는 방식
shell을 통해 Process 생성
./[file_name]
=> ./ 로 경로를 사용하는 이유는, 프로그램만 치면 자체적으로 항상 프로그램을 찾는 위치 (Ex) /usr/bin)이 아니라면 실행이 어렵기 때문이다.
두개 이상의 Process를 순차적으로 사용하기 위해서는 명령어 라인을 ; 을 사용해 한줄로 입력한다.
=> ls ; ./a.out
실행 중인 Process의 목록 확인하기
ps
=> process의 UID PID PPID C STIME TTY TIME CMD 확인 가능
ps 자신은 출력을 보여주는 시점에서는 존재하고 출력이 끝난 후에는 종료된다.
PID 는 Process의 고유한 식별 번호
PPID 는 부모 Process의 식별 번호
Child Process는 Parent Process가 새로 생성 시킨 프로세스를 말한다.
*서로 PID 다르다. 부모 PID는 자식의 PPID가 된다.
UID 는 Process 소유주의 사용자 식별 번호(생성한 사람)
모든 Process는 자신을 생성해준 부모 Process가 있다.
=> 단 init Process는 최초의 프로세스로 없다.
=> init process는 업데이트로 systemd로 대치되었고, 호환성을 위해 init 이라는 symbolic link만 살아있다.
두개 이상의 터미널로 접속하는 경우
tty
몇번째 터미널로 접속했는지 보여준다.
Process 삭제
kill [PID]
Foreground | Background
쉘에서 실행 중인 Process는 Foreground Process와 Background Process로 나뉘어진다.
이는 언제든지 변경이 가능하다.
Foreground Process
사용자의 표준 입력을 받을 수 있다.
하나의 연결 상태에서 한 개의 Process만 Foreground 가능하다
Background Process
실행 중이지만 표준 입력을 받을 수 없는 PRocess
하나의 연결 상태에서 Foreground Process 제외한 나머지 user process
*표준 출력은 모든 Process에서 가능하다.
예제
명령어 라인 끝에 & 입력시 해당 명령은 Background로 전환된다.
ex) cat > 111 &
jobs는 Background에서 실행 중인 작업 목록을 표시한다.(= 작업관리자)
Background process는 각각 %1 %2 등등으로 표시된다.
Foreground Process는 Ctrl + Z 입력해 정지시킨다.
Background로 실행시키기 위해서는 bg %1 등을 해야한다.
fg 명령어를 사용해 Background 실행 작업을 Foreground로 전환시킬 수 있다.
Process를 생성하고 종료하는 System Calls
fork 자신과 완전히 동일한 Process를 생성
exec 지정한 실행 file로부터 Process를 생성한다.
fork
Process를 복제해 동일한 Process를 만든다.(반환값으로 구분)
Process는 실행 파일로 존재하는 프로그램으로부터 생성되는 것이 일반적이나
fork 이용시 실행 중인 Process를 복제해 새로운 Process를 생성할 수 있다.
fork를 호출하는 쪽을 Parent Process , 호출된 쪽을 Child Process라고 한다.
각각 PID가 다른 프로세스이다.
Child Process는 Parent Process가 fork를 호출한 시점의 상태를 그대로 물려받는다.
(Program codes, 프로그램 변수 저장된 데이터 값, Hardware Register 값, Program Stack 값 등등)
#include <sys/types.h>
#include <unistd.h>
pid_t fork (void);
// fork 호출이 성공해 Child Process가 만들어지면 Parent Process에서는 Child Process의 Process ID가 반환 Child Process에서는 0을 반환한다.
// 호출 실패시 Parent Process에서는 -1을 반환한다.
// 호출 이후에 Parent와 Child Process는 각각 자신들의 나머지 프로그램 코드를 수행한다.
fork 호출하는 프로그램의 구조
// fork 호출 이후 부모, 자식 프로세스가 할 일을 구분한다.(반환값으로)
pid = fork();
if(pid == 0)
{
// 자식 프로세스
}
else if(pid > 0)
{
// 부모 프로세스
}
else
{
// fork 실패시 수행할 부분
}
exec
// 경로 이름 또는 파일 이름으로 지정한 실행 파일을 실행하여 Process를 생성한다.
#include <unistd.h>
int execl(const char *path, const char *argv ...);
int execp(const char *file, const char *argv ...);
int execv(const char *path, const char argv[] ...);
int execvp(const char *file, const char argv[] ...);
/*
path 실행 파일의 경로로 상대, 절대 경로 모두 사용 가능하며, 정확한 경로 설정이 필요하다.
file 경로 이름 아닌 실행 파일의 이름
arg path나 file로 지정한 실행 파일로 실행할 때 필요한 명령어 라인의 옵션과 인자 한개 이상을 지정할 수 있으며 마지막 인자는 반드시 NULL 포인터로 지정한다.
argv arg와 같은 의미로 문자형 포인터의 배열로 형태가 다르다. 배열의 마지막은 NULL 문자열로 끝나야 한다.
return 호출 성공시 호출한 프로세스에서 반환 값을 받을 수 있다. 실패시 -1 반환된다.
*/
exec는 지정한 실행 파일로 프로세스를 생성한다.
shell prompt 상에서 ls 실행하는 것과 동일
ex)
ls -l apple/
(shell program 내부)
execlp("ls", "ls", "-l", "apple/", (char *)10);
처음 "ls" => 프로세스를 생성하기 위해 선택된 실행 파일의 이름이고.
나머지 인자들은 main 함수의 *arg ...에 저장되는 문자열들과 동일하다.
==>
./a.elf -a -b -c
main(int argc char *argc)
argc = 4 argv[0] == “./a.elf”, argv[1] == “-a”
Caller Process | Callee Process
caller process 호출 프로세스 => exec 실행 프로세스
callee procee 피호출 프로세스 => exec에 의해 생성되는 프로세스
* exec 호출 후
caller process 종료 => caller process 메모리 영역 callee process가 가져감
=> caller process의 PID를 Callee Process가 받음 => 지위 교체
exec 계열 함수의 구분
1. 함수 이름에 p 가 없는 경우 execl, execv
경로로 실행 파일을 지정 / 지정한 경로에서 해당 파일을 찾음
2. 함수 이름에 p가 있는 경우 execlp, execvp
실행 파일의 이름만 지정 / 쉘 환경 변수 PATH에서 지정한 디렉터리를 차례대로 검색하며 찾음
3. 함수 이름에 l이 있는 경우
옵션을 모두 개별 스트링으로 입력
ex) execlp ("ls","-al","/",NULL);
4. 함수 이름에 v가 들어가면
옵션을 묶어서 스트링 어레이로 입력
ex) char options[10][200] = {"-al", "/", NULL}; execvp("ls", options};
#include <unistd.h>
main()
{
printf("before executing ls -l\n");
execl("/bin/ls", "ls", "-l", (char *)0);
// 인자 나열 끝남
printf("after executing ls -l\n");
// execl 호출이 되면 실행 안함
}
fork vs exec
fork
자신과 동일한 자식 프로세스만 생성
다른 종류의 프로세스 생성 불가. 자식 프로세스를 생성하더라도 종료되지 않음
exec
자신과 다른 종류의 프로세스 생성 가능
새로운 프로세스를 생성하면 자신은 종료
fork와 exec 같이 사용
fork 호출해 자식 프로세스를 생성한 후 자식 프로세스가 exec 호출해 새로운 프로세스 생성해
결과적으로 부모 프로세스는 종류가 다른 자식 프로세스를 생성하고 자신 역시 나머지 작업을 계속할 수 있다.
#include <unistd.h>
#include <sys/types.h>
main()
{
pid_t pid;
printf("hello\n");
pid = fork();
if(pid > 0){
printf("parent\n");
sleep(1);
}
else if(pid == 0) { /* child process */
printf("child\n");
execl("/bin/ls", "ls", "-l", (char *)0);
printf("fail to execute ls\n");
}
else
printf("parent : fail to fork\n");
printf("bye!\n");
}
'프로그래밍 > Linux' 카테고리의 다른 글
[Linux]파일입출력(3) (0) | 2023.10.13 |
---|---|
[Linux]파일입출력(2) (0) | 2023.10.08 |
[Linux]파일입출력(1) (0) | 2023.10.08 |
[Linux]파일시스템 (1) | 2023.10.08 |
[Linux]Debug (0) | 2023.10.08 |