iT邦幫忙

第 12 屆 iThome 鐵人賽

1

記錄學習內容。
以下內容大多引用大大們的文章。
內容可能有錯誤。

程式來源,教學來源:

[Linux C] fork 觀念由淺入深
https://wenyuangg.github.io/posts/linux/fork-use.html

買了這本書,執行緒很詳細:
深入理解Linux程式設計:從應用到核心
https://www.books.com.tw/products/0010756897

OS - Ch3 行程 Process
https://mropengate.blogspot.com/2015/01/operating-system-ch3-processes.html

之前紀錄的
https://ithelp.ithome.com.tw/articles/10228684

筆記:
1
C 的fork 是 產生 process ,不是thread

2
僵屍程序 (Zombie Process):

沒有做任何事, 只是佔著並耗用系統資源 就是 僵屍程序 (Zombie Process)
Zombie Process 會占用 行程ID , 造成系統不能把ID 讓給其他行程 。

這邊的想法是

子行程一下子就完成工作了,但還是活著
因為 父行程 sleep(30秒),沒有 wait(NULL) 來獲取子行程的退出資訊,讓子行程結束。
造成 子行程在30秒內沒結束 ,讓子行程這段時間 變成 Zombie Process
程式:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(){

    pid_t PID = fork();

    switch(PID){
        case -1:
            perror("fork()");
            exit(-1);
        case 0:
            //exit(0);
            break;
        default:
            //wait(NULL); //父行程沒有關掉子行程,讓子行程等父行程sleep(30)後,才一起關掉
            sleep(30);


    }
    printf( "PID is %d\n", getpid());

    return 0;
}

用 ps aux 觀察:

ted      23579  0.0  0.0      0     0 pts/1    Z+   01:24   0:00 [output] <defunct>

所以應該真的是僵屍狀態
http://linux.vbird.org/linux_basic/0440processcontrol.php#ps_l

Z (Zombie):僵屍狀態,程序已經終止但卻無法被移除至記憶體外。

子程序還沒結束 就將 父程序關閉的狀況:

parent 死了,child 會變 orphan(孤兒),parent 睡了,child 事情做完會變 zombie(殭屍)
這種狀況,好像是 orphan(孤兒)

//程式來源:[Linux C] fork 觀念由淺入深
//https://wenyuangg.github.io/posts/linux/fork-use.html

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>


int main(){
    // 從呼叫 fork 開始, 會分成兩支程序多工進行
    pid_t PID = fork();

    switch(PID){
        // PID == -1 代表 fork 出錯
        case -1:
            perror("fork()");
            exit(-1);
        
        // PID == 0 代表是子程序
        case 0:
            printf("I'm Child process\n");
            printf("Child's PID is %d\n", getpid());
            sleep(20);
            break;
        
        // PID > 0 代表是父程序
        default:
            printf("I'm Parent process\n");
            printf("Parent's PID is %d\n", getpid());
    }

    return 0;
}

結果:

I'm Parent process
Parent's PID is 21176
I'm Child process
Child's PID is 21177

子行程還在,但是父行程早就結束了:

20954 pts/1    00:00:00 bash
21177 pts/1    00:00:00 output
21189 pts/1    00:00:00 ps

用 ps aux 觀察

ted      21177  0.0  0.0   4504    72 pts/3    S    01:26   0:00 ./output

S (Sleep):該程式目前正在睡眠狀態(idle),但可以被喚醒(signal)。

3

寫入時複製
https://zh.wikipedia.org/wiki/%E5%AF%AB%E5%85%A5%E6%99%82%E8%A4%87%E8%A3%BD

Copy-on-write 是什麼 ?

如果有多個呼叫者(callers)同時請求相同資源(如記憶體),
他們會共同取得相同的指標指向相同的資源 ,
直到某個呼叫者修改資源的內容時,系統才會真正複製一份專用副本(private copy)給該呼叫者 。

主要的優點是如果呼叫者沒有修改該資源,就不會有副本(private copy)被建立,因此多個呼叫者只是讀取操作時可以共享同一份資源。

子行程 和 父行程 代碼 一模一樣 比較少見 ,所以跟變數比較有關。
意思是說,子行程 的資料(data,變數 ) ,沒有修改的話,就還是跟 父行程 一樣 。
所以就不需要 在複製一份 ,只要指到 和父行程data 一樣的位址,共用記憶體就好了 。
要修改的時候 , 在真正複製一份就好 。

4

父行程 和 子行程 誰先跑 ?
跟這有關:
完全公平排程器
https://zh.wikipedia.org/wiki/%E5%AE%8C%E5%85%A8%E5%85%AC%E5%B9%B3%E6%8E%92%E7%A8%8B%E5%99%A8

可能還是以父行程為主 ,但是也可以調整成 子行程 為主 。
沒有保證 誰先誰後 。

5

execlp,exec,execv

載入特定的binary code 到 memory執行
像是:
execlp("/bin/ls","ls",NULL);

會印出當前目錄下的所有檔案名稱

6

程式:

//程式來源:[Linux C] fork 觀念由淺入深
//https://wenyuangg.github.io/posts/linux/fork-use.html
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(){
    int exit_status;
    int sum = 0;
    pid_t PID = fork();

    switch(PID){
        case -1:
            perror("fork()");
            exit(-1);
        case 0:
            printf("[Child] I'm Child process\n");
            printf("[Child] Child's PID is %d\n", getpid());
            //printf("[Child] Enter my exit status: ");
            //execlp("/bin/ls","ls",NULL); //目錄
            sum += 55;
            //scanf("%d", &exit_status);
            //sleep(3);
            break;
        default:
            printf("[Parent] I'm Parent process\n");
            printf("[Parent] Parent's PID is %d\n", getpid());
            printf("[Parent] child's PID is %d\n", PID);
            //wait(&exit_status);
            // WEXITSTATUS is an macro
            printf("[Parent] Child's exit status is [%d]\n", WEXITSTATUS(exit_status));
            printf("[Parent] sum is [%d]\n", sum);
    }
    printf("%d END \n",PID);

    return 0;
}

可以發現 子行程 和 父行程 都有一份自己的 sum變數

7

測試fork()後,有幾個行程:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(){

    pid_t PID = fork();

    switch(PID){
        case -1:
            perror("fork()");
            exit(-1);
        case 0:
            fork();
	        fork();
    }
    printf("PID is %d\n", getpid());

    return 0;
}

結果:

PID is 20821
PID is 20822
PID is 20824
PID is 20823
PID is 20825

8

【小黑馬作業系統考古】範圍: 恐龍書第一章~第四章
https://ithelp.ithome.com.tw/articles/10229521

程式練習:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(){

    pid_t PID = fork();

    switch(PID){
        case -1:
            perror("fork()");
            exit(-1);
        case 0:
            fork();
	        fork();
            break;
        default:
            fork();
            break;
    }
    if(PID==0) fork();

    printf("PID is %d\n", getpid());
    return 0;
}

結果:

PID is 15097
PID is 15099
PID is 15098
PID is 15103
PID is 15101
PID is 15104
PID is 15100
PID is 15105
PID is 15102
PID is 15106

9 vfork()

fork()、vfork()、clone()系統呼叫差異
https://blog.xuite.net/ian11832/blogg/23967641

fork / vfork 比較
https://jyhshin.pixnet.net/blog/post/26588006

vfork程式練習

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(){

    pid_t PID = vfork();

    switch(PID){
        // PID == -1 代表 fork 出錯
        case -1:
            perror("fork()");
            exit(-1);
        
        // PID == 0 代表是子程序
        case 0:
            printf("I'm Child process\n");
            printf("Child's PID is %d\n", getpid());
            sleep(20);
            break;
        
        // PID > 0 代表是父程序
        default:
            printf("I'm Parent process\n");
            printf("Parent's PID is %d\n", getpid());
    }

    return 0;
}

結果:

I'm Child process
Child's PID is 93
I'm Parent process
Parent's PID is 92

//就是child 會先執行完 ,才換parent 。

如果是fork , 前面的寫法,結果有可能是:

I'm Parent process
Parent's PID is 21176
I'm Child process
Child's PID is 21177

10

vfork 和 execlp("/bin/ls","ls",NULL);練習

int main(){

    pid_t PID = vfork();

    switch(PID){
        // PID == -1 代表 fork 出錯
        case -1:
            perror("fork()");
            exit(-1);
        
        // PID == 0 代表是子程序
        case 0:
            execlp("/bin/ls","ls",NULL); //目錄
            printf("I'm Child process\n");
            printf("Child's PID is %d\n", getpid());
            sleep(20);
            break;
        
        // PID > 0 代表是父程序
        default:
            printf("I'm Parent process\n");
            printf("Parent's PID is %d\n", getpid());
    }

    return 0;
}

結果:

I'm Parent process
Parent's PID is 49

printf 沒加分行符號

代表 行緩衝 ,如果沒有\n ,還會在記憶體裡 ,沒有真正的input, output
,所以會有兩次hello ,因為 child process 把 parent process 的記憶體複製過去了,所以前面的printf還在

// fork3.c
#include <stdio.h>
#include <unistd.h>
int main() {
  pid_t pid;

  printf("hello !");
  // 建立子行程
  pid = fork();

  if (pid == 0) {
    // 子行程
    printf("Child process!\n");
  } else if (pid > 0) {
    // 父行程
    printf("Parent process!\n");
  } else {
    // 錯誤
    printf("Error!\n");
  }

  return 0;
}

結果

hello !Parent process!
hello !Child process!

printf 有分行符號 只會有一個hello

// fork3.c
#include <stdio.h>
#include <unistd.h>
int main() {
  pid_t pid;

  printf("hello ! \n");
  // 建立子行程
  pid = fork();

  if (pid == 0) {
    // 子行程
    printf("Child process!\n");
  } else if (pid > 0) {
    // 父行程
    printf("Parent process!\n");
  } else {
    // 錯誤
    printf("Error!\n");
  }

  return 0;
}
hello ! 
Parent process!
Child process!

上一篇
Bellman Ford Algorithm
下一篇
作業系統 Critical section
系列文
學習筆記46
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言