linux進程學習筆記一--進程控制

進程的經典定義是一個執行中程序的實例。系統中的每個程序都是運行在某個進程上下文中。進程上下文是有程序正確運行所需的狀態組成的,這個狀態包括存放存儲器中的程序代碼和數據、棧、通用寄存器內容、程序計數器、環境變量以及打開文件描述符的集合。

一,linux 進程地址空間

進程爲每個程序提供它自己的私有地址空間,通常與這個地址空間關聯的存儲器字節是不能被其他進程讀或者寫的,linux進程的地址空間如下圖:


二,進程的狀態

每個進程在內核中對應一個task_struct結構體,也稱爲進程描述符,描述進程的所有信息,在linux中進程通常有5種狀態。

Linux進程狀態:R (TASK_RUNNING),可執行狀態。
Linux進程狀態:S (TASK_INTERRUPTIBLE),可中斷的睡眠狀態。
Linux進程狀態:D (TASK_UNINTERRUPTIBLE),不可中斷的睡眠狀態。
Linux進程狀態:T (TASK_STOPPED or TASK_TRACED),暫停狀態或跟蹤狀態。
Linux進程狀態:Z (TASK_DEAD - EXIT_ZOMBIE),退出狀態,進程成爲殭屍進程。
Linux進程狀態:X (TASK_DEAD - EXIT_DEAD),退出狀態,進程即將被銷燬。
三,進程控制

1)獲取進程ID

#include<unistd.h>
#include<sys/types.h>
pid_t getpid(void);
pid_t getppid(void);
返回調用者或父進程的PID

2)創建或終止進程

void exit(int status);
pid_t fork(void);
pid_t vfork(void);

exit函數以status退出狀態來終止進程。

fork函數創建子進程,新創建的子進程得到父進程虛擬地址空間的一份拷貝,包括文本段、數據段、bss段堆以及用戶棧。總之,父進程同子進程有以下特點:併發執行;相同但獨立的地址空間;共享文件。fork函數一次調用卻返回兩次,一次在調用進程中,一次在新創建進程中,在父進程中返回子進程PID,在子進程中返回零。可以通過返回值判斷在父進程還是在子進程中,出錯返回-1。

vfork與fork一樣都創建一個進程,但是它並不是將父進程的地址空間完全複製到子進程中,在子進程調用exec或exit之前,它在父進程的空間中運行。這要就提高了效率。 vfork和fork的另一個區別是:vfork保證子進程先運行,在它調度exex或exit後父進程纔可能被調度運行。

3)回收子進程

#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid,int *statloc,int options);

參數:statloc 指向存放終止狀態單元的指針pid    options  控制wait的操作。

兩個函數的區別:在一個子進程終止前,wait使其調用者阻塞,而waitpid可以設置成調用者不阻塞。waitpid並不等待第一個終止的子進程----它有若干選項,可以控制他等待的進程。

waitpid並不等待在其調用之後的第一個終止進程,它有若干個選項,可以控制它所等待的進程。

對於waitpid函數的參數pid的解釋如下:

  •               pid==-1   等待任一子進程。
  •               pid>0      等待其進程與pid相等的子進程。
  •               pid<-1     等待其組id等於pid絕對值的任一子進程。

options參數使我們能進一步控制waitpid的操作。此參數可以是0,或者是:

  •               WCONTINUED  用於作用控制
  •               WNOHANG          若pid指定的子進程並不是立即可用的,則waitpid不阻塞,此時其返回值爲0。
  •               WUNTRACED       用於作業控制。

4)讓進程休眠

#include<unistd.h>
unsigned int sleep(unsigned int secs);
int pause(void);
sleep返回剩下要休眠的秒數,pause讓調用函數休眠,直到進程收到一信號爲止。

5)加載並運行程序

execve函數在當前進程上下文中加載並運行一個新程序。函數原型如下:

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 *fath,char *const argv[]);
int execvp(const char *file,char *const argv[]);
int execve(const char *file,char *const argv[],char *const envp[]);

用fork函數創建子進程後,子進程往往要調用一種exec函數以執行另一個程序。當進程調用一種exec函數時,該進程完全由新程序代換,而新程序則從其main函數開始執行。因爲調用exec並不創建新進程,所以前後的進程ID並未改變。exec只是用另一個新程序替換了當前進程的正文,數據,堆和棧段。

execve加載file後,調用如下所示的啓動代碼(具體參考深入理解計算機系統第7章),啓動代碼準備好棧,並將控制傳統給新程序的主函數,該主函數有如下形式。

int main(int argc,char*argv[],char**envp);用戶棧組織如下所示。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章