# [作業系統] Ch5 Interlude: Process API
- **system call**:是 user space 與 kernel space 之間的介面
- **UNIX 系統** 提供了不少 **system call**
## fork()
- **用途**:
- 用來創建 child process
- 是 UNIX中唯一一種創建 Process 的方法

- `fork()` System call 在兩個 process 都有回傳值:
- Parent process -> 回傳 child process 的 PID
- Child process -> 回傳 0
- 回傳順序**不固定**
- 因為作業系統模擬**多核心 CPU** 來運行,兩個 process 分別在**不同的核心(Thread, Hart)** 中同時執行
- 可以透過其他 **system call** 來控制回傳先後順序

## wait()
- **用途**:延遲 process 進行
- `wait()` 有回傳值:
- 成功時:會返回 **終止的子行程(child process)** 的 PID,表示是哪個子行程結束了。
- 失敗時:回傳 -1
- 經常用於控制不同 process 的執行優先順序
- 範例:
- **不使用 wait()**
- input
```c=
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
printf("hello world (pid:%d)\n", (int) getpid());
int rc = fork();
if (rc < 0) {
// fork failed; exit
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) {
// child (new process)
printf("hello, I am child (pid:%d)\n", (int) getpid());
} else {
// parent goes down this path (original process)
printf("hello, I am parent of %d (pid:%d)\n",
rc, (int) getpid());
}
return 0;
}
```
- output
```
hello world (pid:961)
hello, I am parent of 962 (pid:961)
hello, I am child (pid:962)
```
- **使用 wait()**:
- input
```c=
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int
main(int argc, char *argv[])
{
printf("hello world (pid:%d)\n", (int) getpid());
int rc = fork();
if (rc < 0) {
// fork failed; exit
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) {
// child (new process)
printf("hello, I am child (pid:%d)\n", (int) getpid());
sleep(1);
} else {
// parent goes down this path (original process)
int wc = wait(NULL);
printf("hello, I am parent of %d (wc:%d) (pid:%d)\n",
rc, wc, (int) getpid());
}
return 0;
}
```
- Output
```
hello world (pid:982)
hello, I am child (pid:983)
hello, I am parent of 983 (wc:983) (pid:982)
```
## exec()
- **用途**:在一程式中用來執行**另一個程式**,並**取代當前程式**
- 在 Linux 中,`exec()` 是一組 system call 的總稱
- `execl()`, `execlp()`, `execle()`, `execv()`, `execvp()`, `execvpe()`
:::warning
比較:
`fork()`:創建一個 child process,與原先的 process(parent process)並存
`exec()`:執行一個新的程式,並**取代**原本的程式
:::
- **應用**:可以跟 `fork()` 搭配,執行新程式並不影響 parent process

## Signal
- Process 之間或作業系統向 process 傳遞的通知或指令
- 例如:
- System call:`kill()` 傳遞**停止**訊號給 process
- Keystroke:
- `Ctrl + C`:傳送 `SIGINT`(終止)給 process
- `Ctrl + Z`:傳送 `SIGTSTP`(暫停)給 process
- `signal()` 與 `sigaction()` 可以用來取得 signal
```c=
// 下方程式用於攔截 SIGINT 訊號
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
// 訊號處理函式
void handle_sigint(int sig) {
printf("收到 SIGINT (Ctrl+C),但程式不會終止。\n");
}
int main() {
signal(SIGINT, handle_sigint); // 設定訊號處理函式
while (1) {
printf("執行中...\n");
sleep(1);
}
return 0;
}
```