Linux系統呼叫——程序控制(C/C++)(Linux)
系統呼叫——程序控制
什麼是程序?
程序是資源分配的最小單元,是一個具有一定獨立功能的程式的一次執行活動。每個程序都是一個獨立的執行單元。
程序與程式的區別?
(1)程式是放到磁碟的可執行檔案,程序是指程式執行的例項。
(2)程序是動態的,程式是靜態的。程式是有序程式碼的集合;程序是程式的執行。通常程序不可在計算機之間遷移;而程式通常對應著檔案、靜態和可以複製
(3)1個程式可以對應多個程序,但1個程序只能對應1個程式。
程序的生命週期?
(1)建立。每個程序都由父程序建立,程序也可建立子程序。
(2)執行。多個程序可以同時存在,程序間可以通訊。
(3)撤銷。
· 最簡單的建立程序的方法就是在終端中輸入 ./test (test是事先編譯好的程式)。
· 在終端輸入命令 ps -elf 可以檢視當前所有程序的資訊,程序ID、父程序ID、程序狀態等
· 為了不讓 test 立即結束可以在 test.c 中編寫程式碼的時候加入 while(1); 保證程式一直執行。
然後使用 ps -elf | grep test 命令可以檢視剛才啟動的程序 ./test
· 對任何一個程序不斷上溯,最終的父程序就是 1號程序Init 。Init的父程序是0號程序,是一個核心程序。
· 在終端輸入命令 kill -9 [程序號]
使用命令 kill -l 可以檢視kill的一些巨集定義
程序執行的三種基本狀態?
程序的執行有三種狀態:
執行狀態:程序正在佔用CPU。
就緒狀態:資源分配就緒。等待分配CPU的處理時間片。
等待狀態:程序不能使用CPU。等待事件發生將其喚醒。
Linux中程序的組成?
Linux中的程序包含3個段,分別為資料段、程式碼段和堆疊段。
資料段,存放的是全域性變數、常量、靜態變數;
程式碼段,存放的是程式的可執行程式碼。
堆疊段,棧存放的是子程式的返回地址、子程式的引數以及程式的區域性變數等。堆
什麼叫程序互斥?
程序互斥是指任何時刻只允許一個程序使用某共享資源。也就是說,對於系統的某個資源,如果有一個程序在使用它,其他程序就必須等待,不能同時使用。
程序排程的方式?
程序排程可分為兩種方式:搶佔式、非搶佔式。後者現在基本看不到。
程序排程是一個很複雜的東西,在此不多作介紹。
排程演算法?
有以下幾種排程演算法:
先來先服務排程演算法
短程序優先排程演算法
高優先順序優先排程演算法
時間片段輪轉演算法
前兩種是早期的使用,現在也是基本看不到了。現在大部分的作業系統都使用的後兩者的結合。
什麼叫死鎖?
死鎖是由於多個程序因競爭資源而形成的一種僵局。若無外力作用,這些程序都將永遠不能向前推進。
什麼叫孤兒程序,什麼叫殭屍程序?
在Linux中,正常情況下,子程序由父程序建立,子程序再建立新的子程序。子程序的結束和父程序的執行是一個非同步過程,即父程序永遠無法預測子程序到底是什麼時候結束。當一個程序完成它的工作終止之後,它的父程序需要呼叫wait()或者waitpid()系統呼叫取得子程序的終止狀態。
孤兒程序:顧名思義,就是沒有了父程序的程序。如果一個父程序退出了,但它的一個或多個子程序還在執行,那麼那些子程序將成為孤兒程序。這些孤兒程序會被init程序接管,並由init程序對它們完成狀態收集工作。
殭屍程序:子程序已經退出,而父程序沒有呼叫wait()或waitpid()獲取這個子程序的狀態資訊,於是父程序就不知道這個子程序有沒有退出結束,也就沒去回收子程序,最終導致子程序的程序描述符仍然儲存在系統中。這種程序稱之為殭屍程序。
總的來看孤兒程序不會有什麼危害,因為孤兒程序最終還有init程序來善後。而殭屍程序如果一直不釋放就會一直佔用程序號,如果大量的產生殭屍程序,將因為沒有可用的程序號導致系統不能產生新的程序,這種情況應該避免。
程序控制函式
1.fork
函式用法 |
#include <sys/types.h> #include <unistd.h> pid_t fork(void); |
---|---|
函式功能 |
建立一個子程序 除了PID和PPID不同,這個子程序複製了父程序的地址空間,並且在父程序作寫操作時再次複製。 但不會繼承父程序的檔案鎖和掛起訊號。 |
函式返回值 |
fork這個函式很特殊,因為它有2個返回值,可能有三個不同的返回值 建立失敗,返回-1, 併產生一個errno 建立成功,子程序返回0,父程序返回子程序的程序id |
程式執行時,父程序和子程序的執行順序是隨機的。在rehat上子程序先執行的概率大一些,在ubuntu上父程序執行的概率大一些。
2.vfork
函式用法 |
#include <sys/types.h> #include <unistd.h> pid_t vfork(void); |
---|---|
函式功能 |
和fork()一樣都是建立一個子程序 有所不同的是vfork()建立的子程序共享了父程序的地址空間。 通常配合exec族函式使用 |
函式返回值 |
建立失敗,返回-1, 併產生一個errno 建立成功,子程序返回0,父程序返回子程序的程序id |
vfork()建立了子程序,在程式執行時一定是子程序優先執行,而且等到子程序執行完了父程序才執行。
vfork()建立的子程序再使用exec呼叫了新程式後,父程序就不需要再等它了。
3.exec族函式
函式用法 |
#include <unistd.h> extern char **environ; int execl(const char *path, const char *arg, ...); |
---|---|
函式功能 |
用被執行的程式替換呼叫它的程式 path&file:被執行的檔名,需要絕對路徑。 arg,...&argv:被執行的程式所需要的命令列引數,包括程式,以空指標NULL結束。 |
函式返回值 |
錯誤返回 -1 併產生一個errno |
exec會啟動一個新程式來替換原有程序,因此程序ID不會改變
4.wait & waitpid
函式用法 |
#include <sys/types.h> pid_t wait(int *status); |
---|---|
函式功能 |
wait的功能是等待任意一個子程序結束(阻塞),然後回收子程序資源。 waitpid的功能是暫時停止目前程序的執行,直到訊號來到或指定的子程序結束。然後回收子程序資源。 status:子程序的狀態 pid:指定的子程序的PID options:通常設定為0 |
函式返回值 |
錯誤返回 -1 併產生一個errno 成功,wait()返回結束的子程序的PID, waitpid()返回狀態改變了的子程序的PID |
WIFEXITED(status)判斷子程序是否正常退出,返回非0
WEXITSTATUS(status)獲取子程序退出狀態
5.exit&_exit
函式用法 |
#include <stdlib.h> void exit(int status); #include <unistd.h> void _exit(int status); |
---|---|
函式功能 |
使程序退出 status:傳遞程序結束狀態,一般來說0表示正常退出 |
函式返回值 |
無返回值 |
_exit()的作用是直接使程序停止,清除其使用的記憶體空間,並清除其在核心的各種資料結構
exit()在執行退出前會檢查檔案的開啟情況,把檔案緩衝區中的內容寫回檔案,即清理I/O緩衝。
6.kill
函式用法 |
#include <sys/types.h> int kill(pid_t pid, int sig); |
---|---|
函式功能 |
傳送訊號 pid:程序ID sig:要傳送的訊號 如果pid有效,kill會把訊號傳送給pid 如果pid=0,kill會把訊號傳送給當前程序所在的程序組的每個程序 如果pid=-1,kill會把訊號傳送給具有傳送訊號許可權的每個程序,除了init 如果pid<-1,kill會把訊號傳送給程序組-pid的每個程序 如果sig=0,kill不會發送訊號,錯誤檢測不會報錯 |
函式返回值 |
錯誤返回 -1 成功返回 0 |
7.raise
函式用法 |
#include <signal.h> int raise(int sig); |
---|---|
函式功能 |
傳送訊號給自己 等同於 kill(getpid(), sig); |
函式返回值 |
錯誤返回 -1 成功返回 0 |
8.signal
函式用法 |
#include <signal.h> typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler); |
---|---|
函式功能 |
處理訊號,及設定訊號的預設處理 訊號的安裝與回覆 signum:要處理的訊號,可以在終端使用kill -l命令檢視有哪些系統巨集定義的訊號 handler:選擇處理訊號的方式,是系統預設SIG_DFL還是忽略SIG_ING還是捕獲(函式入口地址) |
函式返回值 |
錯誤返回 SIG_ERR |
關於忽略SIG_ING,訊號編號 -9 和 -19 是忽略不了的,還有一些特殊的也忽略不了