進程控制

進程創建
fork
從已經存在的進程創建一個進程,新進程稱爲子進程,原進程稱爲父進程,調用此函數子進程返回0,父進程返回子進程的進程ID

進程調用fork之後:
  1. 分配新的內存和數據塊給子進程
  2. 將父進程的數據拷給子進程


調用失敗的原因:
  1. 系統內有太多的進程
  2. 實際用戶的進程數達到了最大值


fork之後父子進程一起執行代碼,但是誰先執行由調度器決定
通常父子進程的代碼共享,當父子進程不在寫入數據的時候,此時數據也共享,但是當父子進程任一方寫入數據時,便以寫時拷貝的方式各自拷貝一個副本

int main()
{
  pid_t ret = fork();
  printf("ret = %d\n,pid = %d\n,ppid = %d\n",ret,getpid(),getppid());
  return 0;
}


vfork
概念:
  1. vfork創建的進程共享同一塊地址空間
  2. vfork後的子進程先執行,在子進程調用完exec之後,父進程再執行
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int g_val = 100;
int main()
{
  pid_t id = vfork();
  if(id == 0)
  {
    g_val = 200;
    printf("before: [%d],pid:[%d],ppid:[%d]\n",g_val,getpid(),getppid());
    exit(0);
  }
  else if(id > 0)
  {
    printf("after: [%d],pid:[%d],ppid:[%d]\n",g_val,getpid(),getppid());
  }
 
  return 0;
}


我們可以發現g_val的值改變了,這就證明事實上父子進程就是共享地址空間

進程終止
退出情況
  1. 代碼運行完成,結果正確
  2. 代碼運行完成,結果不正確
  3. 代碼運行時一場終止

退出方式
  1. 正常退出(main函數返回,調用exit,調用_exit)用echo $? 來查看進程的退出碼
  2. 異常退出(ctrl+c異常終止)

_exit函數(系統調用
  1. 函數原型:void _exit(int status);
  2. status中定義了進程的終止狀態,但是隻有低8位可以用

exit函數
  1. void exit(int status);
  2. 底層還是調用了_exit系統調用
  3. 但是在調用_exit之前,執行清理函數,關閉了所有打開的文件描述符


我們可以畫個圖來理解一下


return:return n 即 exit(n),因爲調用main的函數運行時會將main的返回值當做exit的參數


進程等待
當子進程退出,如果父進程不管不顧,此時子進程就會變成殭屍進程,造成內存泄漏,並且此時用kill指令也殺不死這個進程,因爲誰也沒辦法殺死一個已經死去的進程,此時進程等待就尤爲重要

進程等待的方法
  1. pid_t wait(int status):成功返回進程等待的子進程的id,失敗返回-1,輸出型參數,得到進程的返回狀態
  1. pid_t waitpid(pid_t pid,int status,int options);正常返回等待進程的pid,調用出錯返回-1
  2. 此時的進程等待都是阻塞式等待,就是隻要子進程沒有結束,那麼父進程就一直啥也不幹,就一直等待子進程結束

在進程等待的時候
  1. 當我們使用wait,waitpid等待進程的時候,如果等待的該進程已經退出的話,那麼函數直接返回,釋放資源,獲得子進程的退出信息
  2. 如果在任意時刻調用wait/waitpid的時候,如果子進程沒有退出且正在運行,那麼父進程就會一直阻塞式的等待
  3. 如果不存在該進程,那麼直接出錯返回

獲取子進程的退出狀態(status)
  1. status:我們可以用命令echo $?  獲取到現在爲止的最近的進程的退出狀態,它是一個輸出型參數,我們可以把它當做一個位圖來理解

這張圖只是status的低16比特位,那在代碼裏我們也可以這樣獲取進程的退出狀態

正常退出:status & 0x7f == 0; 獲得進程的退出碼:(status >>8) &0xff
異常退出狀態:返回一個終止的信號碼:status & 0x7f


進程的程序替換
我們在用fork創建子進程之後,子進程執行的是和父進程相同的代碼,但有可能是代碼的不同分段,所以子進程往往要帶哦用exec函數(一簇代碼,並不是一個代碼)去執行其他的代碼。當進程調用exec函數的時候,進程的數據和代碼全部被新程序替換,從新的代碼開始執行,但是調用exec函數不會產生新進程,所以該子進程的進程ID是沒有改變的

我們來了解一下這6個exec函數


path:路徑 
file:文件名
argv:參數所用的數組
envp:環境變量表
這些函數執行成功了之後不會返回任何東西,但是一旦執行失敗,則會返回-1

發佈了55 篇原創文章 · 獲贊 17 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章