1. 程式人生 > >Linux系統呼叫——程序控制(C/C++)(Linux)

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, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);

函式功能

用被執行的程式替換呼叫它的程式

path&file:被執行的檔名,需要絕對路徑。

arg,...&argv:被執行的程式所需要的命令列引數,包括程式,以空指標NULL結束。

函式返回值

錯誤返回 -1 併產生一個errno

        exec會啟動一個新程式來替換原有程序,因此程序ID不會改變 

4.wait & waitpid

函式用法

#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);

函式功能

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>
#include <signal.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 是忽略不了的,還有一些特殊的也忽略不了