程序與程式
程式就是存儲在磁盤上的可執行指令、資料的靜态實體。
程序就是被作業系統讀取、加載到記憶體中的正在執行的程式。
程序的分類
**守護程序:**由系統在開機時通過啟動腳本激活的,總處于活動狀态,一般運作在背景維護系統的正常運作,程序号為1
**批處理程序:**系統會每隔一段時間集中處理該類程序的相關指令,會有一定的延時,但避免了狀态切換的耗時是以執行效率提高。
**互動程序:**在執行時需要使用者輸入一些資料否則無法進行
Linux/UNIX系統檢視程序
簡答形式:ps 以簡略方式顯示目前目前終端有控制權的程序
詳細顯示:ps auwx
a 所有使用者的目前終端有控制權的程序
u 顯示詳細資訊
x 包含無控制權的程序
w 以更高大的列寬顯示
程序的資訊清單
USER 程序屬主
PID 程序IP
%CPU CPU使用率
%MEM 記憶體使用率
VSZ 使用虛拟記憶體的大小(KB)
RSS 使用實體記憶體的大小(KB)
TTY 終端裝置号,如果是?表示無終端控制
STAT 程序的狀态
O 就緒态,所有準備工作都已經完成,等待被系統進行。
R 運作狀态的程序,Linux系統中沒有就緒态,就緒态也用R表示
S 可被喚醒的睡眠,當收到系統終端、擷取到資源、收到信号都可以使程序喚醒轉入運作狀态
D 不可以喚醒的睡眠,隻能被系統調用wake_up喚醒
T 暫停,收到信号SIGSTOP程序将轉為暫停狀态,收到SIGCONT信号轉為進行狀态
Z 僵屍狀态,程序已經結束運作,但其父程序還沒有回收它的資源
s 會話首程序
l 多線程程序
< 高優先級程序
n 低優先級程序
+ 前台程序
START 程序的開始時間
TIME 程序的運作時間
COMMAND 啟動程序的程式
父程序和子程序
1、一個程序可以建立另一個程序,建立者叫父程序,被建立者叫子程序。
2、父程序啟動子程序後,子程序會在作業系統的高度下與父程序同時執行。
3、子程序先于父程序結束時,會向父程序發送SIGCHLD信号,父程序接收到SIGCHLD信号後就應該回收子程序的相關資源,如果父程序沒有及時回收子程序,則子程序會變為僵屍程序。
4、父程序先于子程序結束,子程序就會變成孤兒程序,同時會被init程序收養,即成為init的子程序,而init程序也叫孤兒院。
程序辨別符
1、每個程序都會有一個以非負數表示的唯一的辨別,也就是程序ID,相當于程序的身份證号。
2、程序在任何時候都是唯一的,但可以重用。當一個程序結束時,它的程序ID就可以被其他程序使用(延遲重用)。
pid_t getpid(void);
功能:擷取目前程序的程序ID
pid_t getppid(void);
功能:擷取目前程序的父程序ID
fork建立程序
pid_t fork(void);
功能:建立一個子程序
傳回值:
成功則傳回兩次,子程序傳回0,父程序傳回子程序ID。
失敗則傳回一次 -1
1、通過fork建立的子程序會拷貝父程序的代碼段、資料段、靜态資料段、堆、棧、IO緩沖區
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void func()
{
printf("我是函數%s\n",__func__);
}
int num=0;
int main()
{
static int num_s;
int* p = malloc(4);
pid_t pid = fork();
printf("haha\n");
if(0 == pid)
{
func();
*p = 1234;
num = 1234;
num_s = 1234;
printf("我是子程序%u %p %p %p\n",pid,p,&num,&num_s);
}
else
{
func();
*p = 4567;
num = 4567;
num_s = 4567;
printf("我是父程序%u %p %p %p\n",pid,p,&num,&num_s);
}
}
2、程序建立完成後,父子程序各自獨立進行,先後順序不确定
3、當程序的總數超過系統限制,fork将建立失敗
4、通過fork建立的子程序會繼承父程序的信号處理方式
vfork建立程序
pid_t vfork(void);
功能:建立子程序
傳回值:
失敗傳回 -1
成功傳回兩次,子程序傳回0,父程序傳回子程序ID
差別:
vfork建立的子程序不會複制父程序的代碼段資源,而是通過exec系列函數直接加載一個可執行檔案啟動子程序
子程序建立成功前,子程序暫時借用父程序的相關資源來加載子程序,而此時的父程序是阻塞狀态,隻有子程序建立成功後,父程序才繼續運作。
通過vfork建立的子程序,不會繼承父程序的信号處理方式
int execl(const char *path, const char *arg, ...);
path:可執行檔案的路徑
arg:指令行參數,至少一個,且以NULL結尾
int execlp(const char *file, const char *arg, ...);
file:可執行檔案名,該檔案必須存儲在path環境變量的路徑下
arg:指令行參數,至少一個,且以NULL結尾
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
argv:存儲指令行參數的字元串數組,最後一個必須是NULL
system建立程序
int system(const char *command);
功能:加載一個可執行程式建立子程序
傳回值:成功傳回0,失敗傳回-1
差別:子程序執行時,父程序阻塞,子程序執行結束後父程序才繼續
程序的正常退出
1、從main函數return
2、調用标準C函數exit
無論在任何時候的任何位置調用此函數的程序會立即結束
void exit(int status);
功能:結束目前程序,該函數一旦執行,不會傳回
status:程序的結束狀态碼,與main函數中的傳回值一樣,反映了程序是如何結束的,父程序調用相關函數可以擷取status的低8位,常用的參數:EXIT_SUCCESS,EXIT_FAILURE
程序在執行結束前會先完成以下事情:
先執行atexit/on_exit注冊的函數,然後再調用_exit/_Exit函數
int atexit(void (*function)(void));
int on_exit(void (*function)(int , void *), void *arg);
功能:向核心注冊一個函數,程序結束時自動執行被注冊的函數
void (*function)(int , void *)
int:exit函數的參數或者return傳回的值
void*:on_exit注冊時的第二個參數arg
3、調用_exit/_Exit函數
void _exit(int status)
功能:Linux系統提供的程序結束函數
void _Exit(int status)
功能:标準庫提供的等價于_exit的程序結束函數,目的是為了提高代碼的相容性
1、status可以是exit函數的參數,也可以是使用者提供的,父程序調用相關函數可以擷取status的低8位
2、沖刷所有檔案的緩沖區,關閉所有檔案
3、把子程序托付給init程序收養
4、向父程序發送SIGCHLD信号
4、程序的最後一個線程執行了傳回語句
5、程序的最後一個線程調用了pthread_exit函數
程序的異常終止
1、程序接收到某些信号(他殺)
2、調用abort函數(自殺)
3、最後一個線程對"取消"請求做出響應
回收子程序
pid_t wait(int *status);
功能:等待所有子程序結束,回收子程序,如果所有子程序都在運作,則父程序阻塞
傳回值:
如果沒有子程序則傳回錯誤ECHILD
隻要有一個子程序結束,則傳回子程序的程序ID和狀态碼
pid_t waitpid(pid_t pid, int *status, int options);
功能:等待指定的子程序結束,回收子程序
pid:
< -1 等待程序組号為abs(pid)的程序結束
= -1 等待任意子程序結束
= 0 等待組程序ID為目前程序ID的程序結束
> 0 等待程序ID為pid的程序結束
options:
WNOHANG 如果沒有子程序則立即傳回
WUNTRACED 子程序停止立即傳回
WCONTINUED 子程序由暫停狀态轉為繼續狀态并傳回
傳回值:
如果沒有子程序則傳回錯誤ECHILD
隻要有一個子程序結束,則傳回子程序的程序ID和狀态碼
解析status的宏
WIFEXITED(status) 檢查程序是否正常退出
WEXITSTATUS(status) 擷取status的低八位,但在還有結果為真時才有意義
WIFSIGNALED(status) 檢查程序是否被信号終止
WTERMSIG(status) 擷取導緻程序終止的信号,隻有WIFSIGNALED為真時才有意義
WCOREDUMP(status) 檢查程序是否由于核心轉儲結束(段錯誤),隻有WIFSIGNALED為真時才有意義
WIFSTOPPED(status) 檢查程序是否為暫停狀态
WSTOPSIG(status) 擷取導緻程序暫停的信号,隻有WIFSTOPPED為真時才有意義
WIFCONTINUED(status)當程序由暫停轉換為繼續運作時傳回真
當父程序收到子程序的SIGCHLD信号時,就應該調用wait/waitpid函數回收子程序。
如果子程序已經結束,在調用wai/waited函數之前子程序處于僵屍狀态,調用後子程序會立即消失。
如果不關心子程序結束狀态,status的參數可以為NULL。