進程基本概念及相關函數

進程定義

從不同角度,進程可以有不同定義:

1.進程是程序的一次執行過程

2.進程是一個程序及其數據在處理機上順序執行時所發生的活動。

3.進程是具有獨立功能的程序在數據集合上的運行過程,它是系統進行資源分配和調度的一個獨立單元

fork函數

頭文件:
#include <sys/types.h>
#include <unistd.h>

原型:
 pid_t fork(void);

功能:fork系統調用用於創建一個新進程,稱爲子進程,它與進程(稱爲系統調用fork的進程)同時運行,此進程稱爲父進程。創建新的子進程後,兩個進程將執行fork()系統調用之後的下一條指令。

返回值:在理解返回值之前,我們要明確fork函數作用,fork意思是復刻
,也就意味着一個進程調用fork函數相當於又複製一份一樣的,而原來的進程我們叫做父進程,新產生的進程叫子進程,返回值pid_t代表進程ID,調用一次fork函數相當於有兩個返回值,父進程的fork函數返回子進程id,子進程的fork返回0

案例

//創建5個子進程
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(){
    pid_t pid;
    for(int i = 0; i < 5; i++){
        pid = fork();
        if(pid == -1){
            perror("fork");
            exit(1);
        }
        if(pid == 0){
            printf("i am child , pid = %d,ppid = %d\n",getpid(),getppid());
            break;
        }
    }
    return 0;
}

注意:父子進程間遵循讀時共享寫時複製的原則,也就是當父子進程都對一個變量只讀時,這個變量的空間是一樣的,而進行寫操作時,則是兩個空間

【重點】父子進程共享:1.文件描述符 2.mmap建立的映射區

exec函數族

exec函數族提供了一個在進程中啓動另一個程序執行的方法。它可以根據指定的文件名或目錄名找到可執行文件,並用它來取代原調用進程的數據段、代碼段和堆棧段,在執行完之後,原調用進程的內容除了進程號外,其他全部被新的進程替換了,並且執行時從新程序的啓動例程開始執行。
在這裏插入圖片描述

頭文件:
#include <unistd.h>
原型:
int execl(const char *path, const char *arg, ... /* (char  *) NULL */);
int execlp(const char *file, const char *arg, ... /* (char  *) NULL */);
int execle(const char *path, const char *arg, ... /*, (char *) NULL, char * const envp[] */);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
參數:
path:要執行的程序路徑。可以是絕對路徑或者是相對路徑。在execv、execve、execl和execle這4個函數中,使用帶路徑名的文件名作爲參數。

file:要執行的程序名稱。如果該參數中包含“/”字符,則視爲路徑名直接執行;否則視爲單獨的文件名,系統將根據PATH環境變量指定的路徑順序搜索指定的文件。

argv:命令行參數的矢量數組。

envp:帶有該參數的exec函數可以在調用時指定一個環境變量數組。其他不帶該參數的exec函數則使用調用進程的環境變量。

arg:程序的第0個參數,即程序名自身。相當於argv[O]。

…:命令行參數列表。調用相應程序時有多少命令行參數,就需要有多少個輸入參數項。注意:在使用此類函數時,在所有命令行參數的最後應該增加一個空的參數項(NULL),表明命令行參數結束。

返回值:一1表明調用exec失敗,無返回表明調用成功。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-rSbeZyJz-1585572629939)(/home/liuchenxu/.config/Typora/typora-user-images/1585572542873.png)]

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("========================\n");

    char *argvv[] = {"ls", "-l", "-F", "R", "-a", NULL};
    

    pid_t pid = fork();
    if (pid == 0) {
        execl("/bin/ls", "ls", "-l", "-F", "-a", NULL);
        //while是一個可執行程序
        execl("./while","while",NULL);
        execv("/bin/ls", argvv);
        perror("execlp");
        exit(1);

    } else if (pid > 0) {
        sleep(1);
        printf("parent\n");
    }


    return 0;
}

wait函數

孤兒進程
父進程先於子進程結束, 孤兒進程被init進程領養, init進程變爲孤兒進程的父親
這是爲了釋放進程佔用的系統資源,進程被接收之後, 能夠釋放用戶空間,釋放不了pcb, 必須由父進程釋放
殭屍進程
子進程死了, 父進程還活着, 父進程不去釋放子進程的pcb, 子進程就變成了殭屍進程

頭文件:
#include<sys/types.h>
#include<sys/wait.h>
原型:
pid_t wait (int * status);
功能:
父進程一旦調用了wait就立即阻塞自己,由wait自動分析是否當前進程的某個子進程已經退出,如果讓它找到了這樣一
個已經變成殭屍的子進程,wait就會收集這個子進程的信息,並把它徹底銷燬後返回;如果沒有找到這樣一個子進程
,wait就會一直阻塞在這裏,直到有一個出現爲止。
參數:
參數 status 是一個整形指針。如果status不是一個空指針,則終止進程的終止狀態將存儲在該指針所指向的內存單元中。
如果不關心終止狀態,可以將 status參數設置爲NULL。
返回值:
如果執行成功則返回子進程識別碼(PID),如果有錯誤發生則返回-1。失敗原因存於errno 中。

在這裏插入圖片描述
注意:使用wait函數一次只能回收一個子進程

waitpid函數

頭文件:
#include<sys/types.h>
#include<sys/wait.h>
原型:
 pid_t waitpid(pid_t pid,int * status,int options);
 功能:如果在調用 waitpid()時子進程已經結束,waitpid()會立即返回子進程結束狀態值。
  子進程的結束狀態值會由參數 status 返回,而子進程的進程識別碼也會一起返回。如果不在意結束狀態值,則
參數 status 可以設成 NULL。參數 pid 爲欲等待的子進程識別碼。
參數:
pid<-1 等待進程組識別碼爲 pid 絕對值的任何子進程。
pid=-1 等待任何子進程,相當於 wait()。
pid=0 等待進程組識別碼與目前進程相同的任何子進程。
pid>0 等待任何子進程識別碼爲 pid 的子進程。
參數options提供了一些額外的選項來控制waitpid,參數 option 可以爲 0 或可以用"|"運算符把它們連接起來使用,比如:
ret=waitpid(-1,NULL,WNOHANG | WUNTRACED);如果我們不想使用它們,也可以把options設爲0
返回值:如果執行成功則返回子進程識別碼(PID) ,如果有錯誤發生則返回值-1。失敗原因存於 errno 中。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章