程序是linux作業系統環境的基礎,它控制著系統上幾乎所有的活動。以下我們將**linux多程序程式設計,包括如下內容:
#include #include pid_t fork(void);
該函式的每次呼叫都返回兩次,在父程序中返回的是子程序的pid
,在子程序返回0。呼叫失敗時返回-1,並設定errno
。
fork
函式複製當前程序,在核心程序表中建立乙個新的程序表項。新的程序表項有很多屬性和原程序相同,比如堆指標、棧指標和標誌暫存器的值。但也有許多屬性被賦予了新的值,比如該程序的ppid
被設定成原程序的pid
,訊號點陣圖被清除。
子程序的**與父程序完全相同,同時它還會複製父程序的資料,複製採用的是寫時拷貝,即只有在任一程序(父程序或子程序)對資料執行了寫操作時,複製才會發生(先是缺頁中斷然後作業系統給子程序分配記憶體並複製父程序的資料)。
此外,建立子程序後,父程序中開啟的檔案描述符預設在子程序中也是開啟的,且檔案描述符的引用計數加1。不僅如此,父程序的使用者根目錄、當前工作目錄等變數的引用計數均會加1。
#include extern char** environ;
int execl(const char* path,const char* arg, ...);
int execlp(const char* file,const char* arg, ...);
int execlpe(const char* path, const char* arg, ..., char* const envp);
...
path
引數指定可執行檔案的完整路徑,file
引數可以接受檔名,該檔案的具體位置則在環境表裡path
中搜尋。arg
接受可變引數。envp
用於設定新程式的環境變數。
一般情況下,exec
函式是不返回的,除非出錯。它出錯時返回-1,並設定errno
。如果沒出錯,則原程式中exec
呼叫之後的**都不會執行,因為此時原程式已經被exec
的引數指定的程式完全替換(包括**和資料)。
exec
函式不會關閉原程式開啟的檔案描述符,除非該檔案描述符被設定了類似sock_cloexec
的屬性。
對於多程序程式而言,父程序一般需要跟蹤子程序的退出狀態。因此,當子程序結束執行時,核心不會立即釋放該程序的程序表項,以滿足父程序後續對子程序退出資訊的查詢(如果父程序還在執行)。在子程序結束執行之後,父程序讀取其退出狀態之前,我們稱該子程序處於殭屍態。
另一種使子程序進入殭屍態的情況是:父程序結束或者異常終止,而子程序繼續執行。此時子程序的ppid
將被作業系統設定為1,即init
程序。init
程序接管了該子程序,並等它結束。在父程序退出之後,子程序退出之前,該子程序處於殭屍態。
處於殭屍態的程序佔據著核心資源,下面這組函式在父程序中呼叫,以等待子程序的結束,並獲取子程序的返回資訊,從而避免殭屍程序的產生,或者使子程序的殭屍態立即結束:
#include #include pid_t wait(int* stat_loc);
pid_t waitpid(pid_t pid, int* stat_loc, int options);
wait
函式將阻塞程序,直到該程序的某個子程序結束執行為止,返回結束執行的子程序的pid
,並將該子程序的退出狀態資訊儲存於stat_loc
引數指向的記憶體中。waitpid
只等待有pid
引數指定的子程序。如果pid
取值為-1,那麼它就和wait
一樣等待任意乙個子程序結束,stat_loc
和wait
函式一樣,options
的取值一般為wnohang
,即非阻塞:如果pid
指定的目標子程序還沒有結束或者意外終止,則waitpid
立即返回0;如果目標子程序正常退出了,則waitpid
返回該子程序的pid
。waitpid
呼叫失敗是返回-1並設定errno
。
管道是父程序和子程序間通訊的常用手段。管道能在父、子程序間傳遞資料,利用的是fork
呼叫之後兩個管道檔案描述符(fd[0]
和fd[1]
)都保持開啟。一對這樣的檔案描述符只能保證父、子程序間乙個方向的資料傳輸。如果要實現父、子程序之間的雙向資料傳輸,就必須使用兩個管道。
linux訊號量的api都定義在sys/sem.h標頭檔案中,主要包含3個系統呼叫:semget
、semop
和semctl
。
semget
系統呼叫建立乙個新的訊號量集,或者獲取乙個已經存在的訊號量集。其定義如下:
#include int semget(key_t key, int num_sems, int sem_flags);
semop
系統呼叫改變訊號量的值,即執行p,v操作。
#include int semop(int sem_id, struct sembuf* sem_ops, size_t num_sem_ops);
sem_id
是由semget
呼叫返回的訊號量識別符號,用以指定被操作的目標訊號量集。sem_ops
指向乙個sembuf
結構體型別的陣列,num_sem_ops
指定要執行的操作個數,即sem_ops
陣列中元素的個數。semop
對陣列sem_ops
中的每個成員按照陣列順序依次執行操作,並且該過程是原子操作。semop
成功時返回0,失敗則返回-1並設定errno
。失敗的時候,sem_ops
陣列中指定的所有操作都不被執行。
struct sembuf
sem_num
成員是訊號量集中訊號量的編號,0表示訊號量集中的第乙個訊號量。sem_op
成員指定操作型別,其可選值為正整數、0和負整數。每種型別的操作行為又受到sem_***
成員的影響。sem_***
的可選值是ipc_nowait
和sem_undo
。ipc_nowawit
:無論訊號量操作是否成功,semop
呼叫都將立即返回;sem_undo
:當程序退出時取消正在進行的semop
操作。
semctl
系統呼叫允許呼叫者對訊號量進行直接控制。其定義如下:
#include int semctl(int sem_id, int sem_num, int command, ...);
sem_id
引數是由semget
呼叫返回的訊號量集識別符號,用以指定被操作的訊號量集。sem_num
引數指定被操作的訊號量在訊號量集中的標號。command
引數指定要執行的命令。有的命令需要呼叫者傳遞第4個引數。
數是由semget
呼叫返回的訊號量集識別符號,用以指定被操作的訊號量集。sem_num
引數指定被操作的訊號量在訊號量集中的標號。command
引數指定要執行的命令。有的命令需要呼叫者傳遞第4個引數。
續【伺服器程式設計】linux多程序程式設計(二)
Linux 併發伺服器程式設計(多程序)
在linux中通過流式套接字程式設計 tcp 實現乙個併發伺服器的訪問回顯,適合剛學完linux套接字程式設計的朋友進行鞏固訓練 具體功能 include include include include include include include include include include ...
Linux 併發伺服器程式設計(多程序)
在linux中通過流式套接字程式設計 tcp 實現乙個併發伺服器的訪問回顯,適合剛學完linux套接字程式設計的朋友進行鞏固訓練 具體功能 include include include include include include include include include include ...
linux網路程式設計多程序併發伺服器
伺服器端 include include include include include include include include define port 1234 define maxsize 1024 static int clientprocess int connfd,struct s...