進程基本-進程建立,殭屍進程,exec系列函數

Linux系統中,進程的執行模式劃分爲用戶模式內核模式,當進程運行於用戶空間時屬於用戶模式,
若是在用戶程序運行過程當中出現系統調用或者發生中斷事件,就要運行操做系統(即核心)程序,進程的運行模式就變爲內核模式
在該模式下運行的進程能夠執行機器特權指令,並且該進程的運行不受用戶的干預centos

在Linux操做系統中,經過fork()系統調用來建立子進程數組

目標bash

建立進程數據結構

頭文件函數

#include <unistd.h>spa

函數原型操作系統

pid_t_result=fork(void)指針

參數excel

code

返回值

-1  若是出錯

0  返回到子進程

pid 將子進程的進程id返回給父進程

將執行fork的操做進程稱爲父進程,被fork()建立的進程稱爲該進程的子進程,
當父進程執行fork操做時,操做系統內核執行以下任務完成進程的建立工做:
1.爲子進程分配新的內存塊和內核數據結構
2.複製原來的進程信息到新的進程,即子進程和父進程具備相同的可執行代碼
3.向運行進程集添加新的進程
4.fork執行結束後,將控制返回給2個進程,此時兩個進程可獨立執行,執行順序取決於進程調度

#include <stdio.h>
main(){
    int ret_from_fork,mypid;
    mypid=getpid();
    printf("Before :my pid is %d\n",mypid );
    ret_from_fork=fork();
    sleep(1);
    printf("After:my pid is %5d,ret_from_fork:%5d,parent pid :%5d\n",getpid(),ret_from_fork,getppid());
}
[root@centos1 process]# ./fork
Before :my pid is 22526
After:my pid is 22526,ret_from_fork:22527,parent pid :21968
After:my pid is 22527,ret_from_fork:    0,parent pid :22526

父進程建立子進程後,子進程除了具備相同的代碼段拷貝外,也具備相同的數據段,
即父進程的全局變量名稱和值子進程也會一塊兒拷貝過去,但他們之間是獨立的,可獨立改變相互不受影響

#include <sys/types.h>  //pid_t 類型的在此
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>   //exit 用

int glob=6;  //全局變量

int main(){
    int local;
    pid_t pid;
    local = 8;
    if( (pid=fork()) == 0){
        sleep(2);
    }else if(pid>0){
        glob =60;
        local =80;
        sleep(10);
    }
    printf("glob=%d,local=%d,mypid=%d\n",glob,local,getpid());
    exit (0);
}
[root@centos1 process]# ./var
glob=6,local=8,mypid=22800
glob=60,local=80,mypid=22799

第一行輸出爲子進程,第二行未父進程的輸出,說明父子進程由相同的代碼,但他們變量之間相互不影響

通常狀況下,父進程建立子進程是爲了執行特定的任務,經過執行exec家族系列調用讓子進程執行新的任務
此時,由exec調用提供的命令的指令代碼替換子進程的代碼,至關於對子進程進行了換腦

int execl(const char*path,const char* arg0,const char* arg1,.... NULL)
int execlp(const char*path,const char* arg0,const char* arg1,.... NULL)
int execv(const char*path,const char* argv[])
int execvp(const char*path,const char* argv[])

 

目標

在指定路徑中查找並執行一個文件

頭文件

#include <unistd.h>

函數原型

result=execvp(const *file,const char *argv[])

參數

file 要執行的文件名

argv 字符串數組

返回值

-1 若是出錯

若成功,execvp 沒有返回值

 

 

excel,excelp徹底相同
excev,execvp 徹底相同
excel,excev要求提供可執行文件的絕對路徑或相對路徑名
帶p的 使用$PATH環境變量查找程序
主要區別是:
1.可執行文件的查找方式:不是P結尾的都是完整的目錄路徑,p結尾的可只給出文件名,系統自動從環境變量中進行查找
2.參數的傳遞方式:
有2種方式,逐個列舉;將全部的參數總體構造指針數組傳遞,以函數名第5位字母來區分
l(list)的表示逐個列舉方式 ,語法爲char *arg;
字母爲v(vertor)的表示將全部參數總體構造指針數組傳遞,語法爲: *const argv[]
exec系列調用沒找到和執行文件返回-1 ,否者進程用可執行文件替換它的代碼、數據和堆棧
過程:
1.將制定的程序複製到它的進程
2.用制定的字符串數組做爲argvp[]傳給這個程序
3.運行這個程序

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

main(){
    char *arglist[1];
    pid_t pid;
    arglist[0]="-l";
    arglist[1]="-a";
    printf("parent:%d\n",getpid());
    pid=fork();
    if( pid==0 ){
        printf("son1  pid is:%d\n",getpid() );
        execvp("ls",arglist);
        printf("son2  pid is:%d\n",getpid() );
    }else{
        printf("parnet pid:%d\n",getpid() );
    }
    printf("in %d\n",getpid());
    
}
/**
execvp 後的當前進程的代碼再也不執行
root@centos1 c]# ./exec
parent:26307
parnet pid:26307
in 26307
son1  pid is:26308
[root@centos1 c]# .  ..  exec  exec.c  fork.c  var.c

**/

 殭屍進程

當父進程尚未結束而子進程結束運行,同時父進程沒有使用wait系統調用獲取子進程的結束狀態時
子進程就成爲殭屍進程
父進程先結束不會產生殭屍進程。
殭屍進程沒有任何代碼、數據和堆棧,佔用不了多少資源,但它存在於系統的任務列表中。在進程表裏仍佔了1個位置佔用進程號
通常要避免出現這種狀況
當使用ps查看進程時 若是進程名稱旁邊出現defunct,則代表該進程爲殭屍進程

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

void parent_code(int delay){
    sleep(delay);
}
main(){
    pid_t pid;
    int status;

    pid=fork();
    if(pid == 0){

    }
    if(pid>0){
        parent_code(20);
    }
}
/*
[root@centos1 c]# gcc -o zombie zombie.c 
[root@centos1 c]# ./zombie&
[1] 28577
[root@centos1 c]# ps
   PID TTY          TIME CMD
 25201 pts/0    00:00:00 bash
 28577 pts/0    00:00:00 zombie
 28578 pts/0    00:00:00 zombie <defunct>
 28580 pts/0    00:00:00 ps
 */

爲了防止子進程成爲殭屍進程,通常在父進程調用wait()系統調用等待子進程的結束並獲取子進程的返回狀態
wait調用作2件事:
首先暫停調用它的進程直到子進程結束,而後取得子進程結束時傳給exit的值

目標

等待子進程的結束

頭文件

#include <sys/wait.h>

#include <sys/types.h>

函數原型

pid_t pid=wait(int *status)

參數

status指向一個保存子進程返回狀態的整型變量

返回值

若是不存在子進程,返回-1

如有任何一個子進程結束,則返回該子進程的pid並保存其返回狀態在status中,同時wait調用也結束

#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

void child(int delay){
    sleep(delay);
    exit(0);
}

void parent(int *status){
    wait(status);
}

main(){
    pid_t pid;
    int status;
    printf("Before:%d\n",getpid());
    pid=fork();
    if(pid == 0){
        child(10);
    }
    if(pid >0 ){
        printf("pid =%d\n",getpid());
        parent(&status);
        printf("status =%d\n",status);
    }
}
/*
[root@centos1 c]# ./a.out
Before:14901
pid =14901
status =0

*/

 

上述代碼可防止殭屍進程的產生
waitpid()亦可實現wait()調用相似功能
多數狀況下會使用waitpid()
他們的主要區別是:
1.wait()只能獲得任何一個子進程結束的狀態,當一個父進程有多個子進程時,在某個子進程結束,則wait可獲得其結束狀態
此時沒法再獲得其它子進程的結束狀態,此時容易產生其它子進程的殭屍進程
2.wait()調用屬於阻塞調用,父進程執行該指令後,器等待子進程結束以後才能執行它後面的代碼,
而waitpid()可提供非阻塞調用的方式
3.waitpid()調用能夠等待指定的子進程具備比wait多的功能

目標

等待某個子進程的結束

頭文件

#include <sys/wait.h>

#include <sys/types.h>

函數原型

pid_t pid=waitpid(pid_t pid,int *status,int options)

參數

pid=-1 等待任一個子進程.wait等效

pid>0 等待進程idpid的子進程

pid=0 等待其組id等於調用進程組id的任一子進程

pid<-1 等待其組id等於pid絕對值的任一進程

options選項:

WNOHANG 表示若是沒有任何已經結束的子進程則立刻返回,不等待

WUNTRACED 若是子進程進入暫停執行狀況則立刻返回,但結束狀態不予以理會

0 做用和wait同樣,阻塞父進程,等待子進程結束

 

 

返回值

若是不存在子進程,返回-1

如有指定子進程結束,則返回該子進程的pid並保存其返回狀態在status,同時waitpid調用也結束

子進程退出狀態檢測的宏

說明

WIFEXITED(status)

若是子進程正常結束,則爲非0,此時可調用WEXITSTATUS(status)

取得子進程exit()返回的結束代碼

WIFSIGNALED(status)

若是子進程是由於信號則此宏的值爲真,

此時可用WIERMSIG(status)取得子進程因信號而終止的信號代碼

WIFSTOPPED(status)

若是子進程處於暫停執行狀況則此宏爲真.採用WSTOPPSIG(status)

取得引起子進程暫停的信號代碼

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息