# [作業系統] Ch5 Interlude: Process API - **system call**:是 user space 與 kernel space 之間的介面 - **UNIX 系統** 提供了不少 **system call** ## fork() - **用途**: - 用來創建 child process - 是 UNIX中唯一一種創建 Process 的方法 ![image](https://hackmd.io/_uploads/SylVReGH31l.png) - `fork()` System call 在兩個 process 都有回傳值: - Parent process -> 回傳 child process 的 PID - Child process -> 回傳 0 - 回傳順序**不固定** - 因為作業系統模擬**多核心 CPU** 來運行,兩個 process 分別在**不同的核心(Thread, Hart)** 中同時執行 - 可以透過其他 **system call** 來控制回傳先後順序 ![image](https://hackmd.io/_uploads/HJ3VizH21l.png) ## 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 ![image](https://hackmd.io/_uploads/HJ3VizH21l.png) ## 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; } ```