十八、Linux 進程與信號---進程介紹
阿新 • • 發佈:2018-06-02
控制 HR struct bsp 進程控制 start 否則 文件寫入 內核
18.1 進程的概念
- 程序:程序(program)是存放再磁盤文件中的可執行文件
- 進程
- 程序的執行實例被稱為進程(process)
- 一個程序的執行實例可能由多個
- 進程具有獨立的權限和職責。如果系統中某個進程崩潰,它不會影響到其余的進程。
- 每個進程運行在其各自的虛擬地址空間中,進程之間可以通過由內核控制的機制相互通訊
- 進程ID
- 每個 Linux 進程都一定由一個唯一的數字標識符,稱為進程ID(process ID),進程ID總是一非負整數
18.2 內核中的進程結構體
每一個啟動進程都有一個 task_struct 結構,這是個結構體,命名為進程表項(或 進程控制塊)如下:
啟動一個程序操作文件的過程如下:進程啟動創建一個 task_struct 進程表項,進程表項中有一個成員指向文件描述符表
18.3 進程的啟動和終止
進程的啟動和退出如下:
main 運行的時候,內核會幫忙啟動一個例程(C start template),啟動例程會幫忙啟動 main 函數,並幫忙收集命令行參數,環境參數等等,調用結束以後,main 返回給啟動例程。
若是調用 exit() 函數,就不會返回給main 函數或其他函數了。exit() 直接調用內核所提供的系統調用退出函數。
atexit 函數為註冊退出函數。
18.3.1 內核啟動特殊例程
- 啟動例程
- 在進程的 main 函數執行之前內核會啟動
- 該例程放置在 /lib/libc.so.*** 中
- 編譯器在編譯時會將啟動例程編譯進可執行文件中
-
啟動例程的作用
- 搜集命令行的參數傳遞給 main 函數中的 argc 和 argv
- 搜集環境信息構建環境表並傳遞給 main 函數
- 登記進程的終止函數
18.3.2 進程的終止方式
-
正常終止
- 從main 函數返回 return
- 調用 exit (標準C 庫函數)
- 調用 _exit 或 _Exit(系統調用)
- 最後一個線程從其啟動例程返回
- 最後一個線程調用 pthread_exit
-
異常終止
- 調用 abort
- 接受一個信號並終止
- 最後一個線程對取消請求做處理響應
-
進程返回
- 通常程序運行成功返回0,否則返回 非 0
- 在 shell 中可以查看進程返回值( echo $?)
進程終止方式區別
18.3.2.1 內核登記進程終止函數---atexit 函數
1 #include <stdlib.h> 2 int atexit (void (*function)(void));
- 相關函數 _exit,exit,on_exit
- 函數說明:
- atexit()用來設置一個程序正常結束前調用的函數。
- 當程序通過調用exit()或從main中返回時,參數function所指定的函數會先被調用,然後才真正由exit()結束程序。
- 函數功能
- 向內核登記終止函數
- 返回值:
- 如果執行成功則返回0,否則返回-1,失敗原因存於errno中。
- 其他說明
- 每個啟動的進程都默認登記了一個標準的終止函數
- 終止函數在進程終止時釋放進程所占用的一些資源
- 登記的多個終止函數執行順序是以 棧的方式執行,先登記的後執行
18.3.2.2 例子
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <string.h> 4 #include <stdlib.h> 5 #include <fcntl.h> 6 7 //定義進程的終止函數 8 void term_fun1(void) 9 { 10 printf("first term function\n"); 11 } 12 13 void term_fun2(void) 14 { 15 printf("second term function\n"); 16 } 17 18 void term_fun3(void) 19 { 20 printf("third term function\n"); 21 } 22 23 int main(int argc, char *argv[]) 24 { 25 if(argc < 3) { 26 fprintf(stderr, "usage: %s file [exit | _exit | return]\n", argv[0]); 27 exit(1); 28 } 29 30 //向進程登記終止函數 31 atexit(term_fun1); 32 atexit(term_fun2); 33 atexit(term_fun3); 34 35 FILE *fp = fopen(argv[1], "w+"); 36 fprintf(fp, "hello world"); 37 38 if(!strcmp(argv[2], "exit")) { 39 exit(0);//標準C 的庫函數 40 } else if(!strcmp(argv[2], "_exit")) { 41 _exit(0);//系統調用 42 } else if(!strcmp(argv[2], "return")) { 43 return 0; 44 } else { 45 fprintf(stderr, "usage: %s file [exit | _exit | return]\n", argv[0]); 46 } 47 48 exit(0); 49 }
結果是前兩種可以正常運行,並且對文件可以正常寫入,但是第三種方式無輸出,且文件創建了,但沒有寫入。
而且可以看見終止方式是以棧的方式進行調用的。
可以知道選用 _EXIT和_exit 系統調用的時候,不會進行調用。之所以沒有輸出,代碼中向文件寫入數據的時候,表現為全緩存,這些數據可能還存放在緩存中,並沒有從緩存中釋放出來。帶代碼中加入 fclose 函數或程序終止後,會自動清緩存,但是系統調用 _exit 和 _EXIT 不會自動刷新緩存。
十八、Linux 進程與信號---進程介紹