프로세스는 실행 중인 프로그램을 의미합니다.
여기서 프로그램이란 소스 코드를 바이너리 코드로 컴파일해서 생성한 일련의 기계어 명령어이고, 실행된다는 것은 명령어들을 메모리에 로드하고 CPU가 그것을 하나씩 실행하는 것을 의미합니다.
ps 명령어는 현재 실행 중인 프로세스의 상태를 출력합니다.
ps

ps -a: 다른 사용자 및 다른 터미널에서 실행되는 프로세스도 출력
ps -la: long format

1. F: process Flag(no longer used)
2. S: 각 프로세스의 상태
- S: Sleeping
- R: Running
3. UID: User ID
4. PID: Process ID
5. PPID: Parent Process ID
6. PRI: PRIority (숫자가 높을 수록 우선 순위가 낮음)
7. NI: NIceness level
- -20(not nice to other) ~ 19(nicest)
- 높은 nice 번호를 가진 프로세스는 CPU 시간을 양보
8. SZ: process memory SiZe (KB)
ps -fa: full-format listing (UID 대신 사용자 이름 표시)
Unix 시스템의 메모리는 kernel space와 user space로 나뉩니다.
Kernel: 하드웨어 관리를 하며, user가 요청하는 서비스를 처리합니다. 또한 이 공간에서 문제가 생기면 시스템 전체에서 문제가 생길 수 있으므로 일반 사용자는 접근할 수 없으며, 함수를 이용해 간접적인 접근만이 가능합니다.
User: 제한된 접근만이 가능하며, 문제가 생겨도 시스템에는 영향이 없습니다. 사용자 프로그램을 실행하는 역할을 합니다.
Process는 그 중 user space에서 동작하는데, 작은 단위의 page로 나뉘어서 allocation list를 관리합니다.
Kernel은 프로그램의 기계어 코드와 데이터를 보관할 memory page를 검색하고, 프로세스의 메모리 할당 정보와 속성들을 저장하기 위한 data structure를 설정합니다.

Shell은 프로세스 관리 및 프로그램을 실행하는 프로그램입니다.
3개의 주요한 기능이 있는데, 이는 다음과 같습니다.
프로그램 실행 (./out)

입출력 관리
프로그래밍(Shell programming)
$ for((num=0;num<3;num++)
> do
> echo "num: $num"
> done
num: 0
num: 1
num: 2
위와 같은 프로그래밍이 가능
프로그램을 실행하고 그 프로그램에서 또 다른 프로그램을 실행해야하는 경우가 발생할 수 있다. 그럴 때 우리는 어떠한 방법을 사용할 수 있을까?
usage: execvp(cont char *file, cont char *argv[])

fork()
이미 실행 중인 프로세스를 복사해서 동일한 새로운 프로세스를 생성
kernel 동작 과정
예시 코드
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){
pid_t mypid = getpid();
printf("Before: my pid is %d\n", mypid);
pid_t ret_from_fork = fork();
sleep(1);
printf("After: my pid is %d, fork() said %d\n",
getpid(), ret_from_fork);
return 0;
}

fork() 함수가 실행된 뒤에는 실행된 그 자리에서부터 남은 코드가 시작된다.
위의 예제 코드에서 Before: ~~ 가 두 번 출력되지 않는 것도 그 이유 때문이다.
만약 코드의 처음부터 다시 시작하는 구조였다면 fork()는 무한히 자기 자신을 호출하는 재귀함수가 될 것이다.
자식 process가 return(exit)한 값을 저장
wait() 함수에는 두 가지 기능이 있음
Kernel은 자식 프로세스의 종료 상태 정보를 2바이트(16비트) 정수 값으로 저장

Shell이 프로그램을 실행하는 과정을 정리해보면 이렇습니다.

또한 하나의 프로세스에서 복제된 프로세스 내부의 프로그램이 실행되고 있을 때, SIGINT signal이 발생하면 모든 프로세스가 종료된다.
이는 signal과 tty의 특성인데, tty에서 발생한 signal은 해당 tty를 사용하는 모든 프로세스에게 발생하기 때문에 다 종료되는 것이다.
덧붙여서 서로 다른 2개의 tty에서 같은 프로그램을 실행 중일 때, 어떤 하나의 tty에서 signal을 발생시킨다고 해서 나머지 하나의 tty에는 영향을 주지 않는다.

| Usage | Example |
|---|---|
| execv(fullpath, arglist) | char *arg[4]={“ls”, “-l”, “./demodir”, NULL}; execvp("/bins/ls", arg); 와 동일한 기능 |
| execvp(file, arglist) | char *arg[4]={“ls”, “-l”, “./demodir”, NULL}; |
| execve(fullpath, arglist, envlist) | char *args[] = {"/show_envp" , "HTTP", NULL}; char *env[] = {"HTTP=knu.ac.kr", NULL}; |
| execl(fullpath, arg0, arg1, …, NULL) | execl(“/bin/ls”, “ls”, “-l”, “./demodir”, NULL) |
| execlp(file, arg0, arg1, …, NULL) | execlp(“ls”, “ls”, “-l”, “./demodir”, NULL) |