Linux學習記錄--進程控制相關係統調用

wKioL1NPPCHz5VO-AAO9CABrvqw134.bmp

系統調用:進程控制

fork系統調用


函數作用:創建一個子進程

形式:pid_tfork(void);

      pid_t vfork(void);

說明:使用vfork創子進程時,不會進程父進程的上下文

返回值:[返回值=-1]子進程創建失敗

       [返回值=0]子進程創建成功

       [返回值>0]對父進程返回子進程PID



#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
int main() {
    pid_t id = fork();
    if (id < 0) {
        perror("子進程創建失敗!");
    } else {
        if (id == 0) {
            printf("子進程工作:PID=%d,PPID=%d\n", getpid(), getppid());
        }else
        {
            printf("父進程工作:PID=%d,PPID=%d,子進程PID=%d\n", getpid(), getppid(),id);
            sleep(5)
        }
    }
}


控制檯輸出

父進程工作:PID=3173,PPID=2432,子進程PID=3176

子進程工作:PID=3176,PPID=3173


exit系統調用


函數作用:終止發出調用的進程

形式:voidexit(int status);

說明

1.      exit返回信息可由wait系統函數獲得

2.      如果父進程先退出子進程的關係被轉到init進程下


#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
    pid_t id = fork();
    if (id < 0) {
        perror("子進程創建失敗!");
    } else {
        if (id == 0) {
            printf("子進程工作:PID=%d,PPID=%d\n", getpid(), getppid());
            sleep(20);
            printf("此時子進程:PID=%d,PPID=%d\n", getpid(), getppid());
        }else
        {
            printf("父進程工作:PID=%d,PPID=%d,子進程PID=%d\n", getpid(), getppid(),id);
            sleep(5);
            exit(3);
        }
    }
    return 0;
}


控制檯輸出

父進程工作:PID=3068,PPID=2432,子進程PID=3071

子進程工作:PID=3071,PPID=3068

此時子進程:PID=3071,PPID=1


wait系統調用


函數作用:父進程與子進程同步,父進程調用後。進入睡眠狀態,直到子進程結束或者父進程在被其他進程終止,

形式:pid_twait(int *status)

pid_t waitpid(pid_t pid ,int *status,int option)

參數:statusè exit是設置的代碼

pid è進程號

option: WNOHANG|WUNTRACED


WNOHANG:,即使沒有子進程退出,它也會立即返回,不會像wait那樣永遠等下去.
WUNTRACED:子進程進入暫停則馬上返回,但結束狀態不予以理會.

返回值:如果成功等待子進程結束,則返回子進程PID。後者爲-1


用來檢查子進程返回狀態的宏

WIFEXITED這個宏用來指出子進程是否爲正常退出的,如果是,它會返回一個非零值.

WEXITSTATUS當WIFEXITED返回非零值時,我們可以用這個宏來提取子進程的返回值


wait函數使用

#include <sys/types.h>
#include <sys/uio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
    pid_t cid;
    cid = fork();
    if (cid < 0) {
        perror("子進程創建失敗!");
    } else {
        if (cid == 0) {
            printf("子進程工作\n");
            printf("子進程PID=%d,PPID=%d\n", getpid(),getppid());
            //sleep(20); //1
        } else {
            //wait(NULL);//2
            //sleep(20);//3
            printf("父進程工作\n");
            printf("父進程PID=%d,PPID=%d\n", getpid(),getppid());
        }
    }
    return 0;
}


針對上述代碼作以下分析:

1.       當子進程退出時,如果父進程沒有wait進行回收資源,子進程就會一直變爲殭屍進程(Z)直到父進程退出

作法:

打開3處註釋後執行程序,查看進程狀態,如下

[root@localhostDebug]# ps -C Process -o pid,ppid,stat,cmd

PID PPID STAT CMD

12233 11563S   /root/workspace/Process/Debug/Process

12238 12233Z    [Process] <defunct>

=>可以看到子進程此時的狀態時Z(殭屍進程)


控制檯輸出如下

子進程工作

子進程PID=12238,PPID=12233

20S…..

父進程工作

父進程PID=12233,PPID=11563


2.       使用wait進行進程同步,父進程直到子進程退出,wait纔會結束等待

作法:

打開12處註釋後執行程序,查看進程狀態,如下

[root@ Debug8$] ps -C Process -o pid,ppid,stat,cmd

PID PPID STAT CMD

3425 2432 S   /root/workspace/Process/Debug/Process

3430 3425 S   /root/workspace/Process/Debug/Process

=>父進程與子進程都處於sleep狀態


控制檯輸出如下

子進程工作

子進程PID=3430,PPID=3425

20S…..

父進程工作

父進程PID=3425,PPID=2432


3. 使用wait進行進程同步,子進程退出後,父進程結束wait等待,同時清空子進程信息,此時子進程不再是殭屍進程

作法:

打開23處註釋後執行程序,查看進程狀態,如下


[root@localhostDebug]# ps -C Process -o pid,ppid,stat,cmd

 PID PPID STAT CMD

1250611563 S   /root/workspace/Process/Debug/Process

=>可以看到此時只有父進程信息


控制檯輸出如下

子進程工作

子進程PID=12511,PPID=12506

20S…..

父進程工作

父進程PID=12506,PPID=11563


WEXITSTATUS與WIFEXITED宏的使用

#include <sys/types.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
    pid_t cid;
    int pr, status;
    cid = fork();
    if (cid < 0) {
        perror("子進程創建失敗!");
    } else {
        if (cid == 0) {
            printf("子進程工作PID=%d,父進程PID=%d\n", getpid(),getppid());
            sleep(20);
            exit(3);
        } else {
            pr = wait(&status);
            if (WIFEXITED(status)) {
                printf("父進程工作PID=%d\n", getpid());
                printf("WAIT返回值=%d\n", pr);
                printf("子進程正常退出PID=%d\n", getpid());
                printf("WIFEXITED(status)=%d\n", WIFEXITED(status));
                printf("WEXITSTATUS(status)=%d\n", WEXITSTATUS(status));
            } else {
                printf("子進程異常退出PID=%d,信號=%d\n", getpid(), status);
                printf("WAIT返回值=%d\n", pr);
            }
        }
    }
    return 0;
}


基於上面代碼做出分析:


1.       子進程正常退出

控制檯輸出信息如下:

子進程工作PID=12070,父進程PID=12069

(20S後…..)

父進程工作PID=12069

WAIT返回值=12070

子進程正常退出PID=12069

WIFEXITED(status)=1

WEXITSTATUS(status)=3


2.       子進程異常退出

作法:

運行程序,在子進程SLEEP期間,殺死子進程

[root@localhost Debug]# kill -9 11990


控制檯臺輸出如下

子進程工作PID=11990,父進程PID=11985

(kill -9 PID 殺死子進程)

子進程異常退出PID=11985,信號=9

可以看出子進程正常退出時,status返回值是exit的退出值,子進程異常退出時status返回值信號值


waitpid函數使用


waitpid的參數說明


參數pid的值有以下幾種類型:
pid>0時,只等待進程ID等於pid的子進程,不管其它已經有多少子進程運行結束退出了,只要指定的子進程還沒有結束,waitpid就會一直等下去.
pid=-1時,等待任何一個子進程退出,沒有任何限制,此時waitpid和wait的作用一模一樣.
pid=0時,等待同一個進程組中的任何子進程,如果子進程已經加入了別的進程組,waitpid不會對它做任何理睬.
pid<-1時,等待一個指定進程組中的任何子進程,這個進程組的ID等於pid的絕對值.


參數options的值有以下幾種類型:
如果使用了WNOHANG參數,即使沒有子進程退出,它也會立即返回,不會像wait那樣永遠等下去.
如果使用了WUNTRACED參數,則子進程進入暫停則馬上返回,但結束狀態不予以理會.
如果我們不想使用它們,也可以把options設爲0,如:ret=waitpid(-1,NULL,0);


WNOHANG使用

#include <sys/types.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
    pid_t cid;
    int pr, status;
    cid = fork();
    if (cid < 0) {
        perror("子進程創建失敗!");
    } else {
        if (cid == 0) {
            printf("子進程工作PID=%d\n", getpid());
            sleep(5);
            exit(3);
        } else {
            do{
                pr = waitpid(0,&status, WNOHANG);
                if(pr==0)
                {
                 printf("沒有子進程退出,繼續執行..\n");
                 sleep(1);
                }
            }while(pr==0);
            printf("子進程正常退出PID=%d\n", pr);
        }
    }
    return 0;
}

控制檯輸出:


沒有子進程退出,繼續執行..

子進程工作PID=3632

沒有子進程退出,繼續執行..

沒有子進程退出,繼續執行..

沒有子進程退出,繼續執行..

沒有子進程退出,繼續執行..

子進程正常退出PID=3632


針對某一進程進行等待

#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
    pid_t cid;
    int pr, status;
    cid = fork();
    if (cid < 0) {
        perror("子進程創建失敗!");
    } else {
        if (cid == 0) {
            printf("子進程工作PID=%d,PPID=%d\n", getpid(), getppid());
            sleep(20);
            exit(3);
        } else {
            pr = waitpid(cid, &status, 0);
            printf("父進程正常退出PID=%d\n", pr);
        }
    }
    return 0;
}

控制檯輸出

子進程工作PID=4257,PPID=4252

父進程正常退出PID=4257


WUNTRACED 使用

#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
    pid_t cid;
    int pr, status;
    cid = fork();
    if (cid < 0) {
        perror("子進程創建失敗!");
    } else {
        if (cid == 0) {
            printf("子進程工作PID=%d,PPID=%d\n", getpid(), getppid());
            sleep(30);
            exit(3);
        } else {
            pr = waitpid(cid, &status, WUNTRACED);
            printf("父進程正常退出PID=%d,status=%d\n", pr,status);
        }
    }
    return 0;
}

作法:在子進程SLEEP時,通過SHELL命令停止子進程

[root@ ~ 6$] kill -STOP PID


控制檯輸出

子進程工作PID=4110,PPID=4108

(SLEEP期間,停止子進程)

父進程正常退出PID=4110,status=4991

在查看進程狀態,發現此時父進程子進程都已經退出

[root@ Debug 13$] ps -C Process -opid,ppid,stat,cmd

PID  PPID STAT CMD


exec系統調用


函數作用:以新進程代替原有進程,但PID保持不變

形式:

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 *path, char *constargv[]);

int execvp(const char *file, char *constargv[]);

int execve(const char *path, char *constargv[], char *const envp[]);


舉例:

exec1.c
#include <stdio.h>
#include <unistd.h>
int main()
{
  printf("這是第一個進程PID=%d\n",getpid());
  execv("e2",NULL);
  printf("asa");
  return 0;
}
exec2.c
#include <stdio.h>
#include <unistd.h>
int main()
{
  printf("這是第二個進程PID=%d\n",getpid());
}


運行結果:

[root@ Process 9$] gcc -o e1 exec1.c

[root@ Process 10$] gcc -o e2 exec2.c

[root@ Process 11$] ./e1

這是第一個進程PID=3051

這是第二個進程PID=3051




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