3.进程

一.fork()

fork()用来创建一个子进程,子进程复制父进程的0-3G空间和父进程内核中的PCB,但子进程和父进程的id号不同。

fork()调用一次,返回两次

在父进程中返回子进程的PID,在子进程中返回0。

例:

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

int main()
{
    pid_t pid;
        
    pid = fork();
    if (pid > 0) {
        printf("cur process is parent\n");
        printf("cur pid is: %d\n", getpid());
        printf("cur parent pid is: %d\n", getppid());
        while(1);
    } else if (pid == 0) {
        printf("cur process is child\n");
        printf("cur pid is: %d\n", getpid());
        printf("cur parent pid is: %d\n", getppid());
        while(1);
    } else {
        perror("fork");
    }
    
    return 0;
}

运行结果:

cur process is parent
cur pid is: 5924
cur parent pid is: 2736
cur process is child
cur pid is: 5925
cur parent pid is: 5924

二.execl()&execv()&execle()&execve()&execlp()&execvp()

char *const ps_argv[] ={"ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL};
char *const ps_envp[] ={"PATH=/bin:/usr/bin", "TERM=console", NULL};
execl("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);
execv("/bin/ps", ps_argv);
execle("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL, ps_envp);
execve("/bin/ps", ps_argv, ps_envp);
execlp("ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);
execvp("ps", ps_argv);

PS:

1.只有execve是真正的系统调用,其它五个函数最终都调用execve

2.由于exec函数只有错误返回值,只要返回了一定是出错了,所以不需要判断它的

返回值,直接在后面调用perror即可

例:

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

int main()
{
    
    // execl("/bin/ls", "ls", "-l", NULL);
    char *const ps_argv[] = {"ps", "aux", NULL};
    //execvp("ps", ps_argv);
    execlp("ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);
    perror("exec ps");
    exit(1);
    return 0;
}

运行结果:

PID PPID PGRP SESS TPGID COMMAND
2699 2693 2699 2699 3926 bash
3926 2699 3926 2699 3926 ps

三.wait()&waitpid()

◆ wait()

僵尸进程: 子进程退出,父进程没有回收子进程资源(PCB),则子进程变成僵尸进程(Z+)(当子进程运行结束后,其用户空间已被释放,但它的PCB没有被立即释放,等待父进程将其释放)
孤儿进程: 父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为1号进程init进程,称为init进程领养孤儿进程

可使用wait()函数除去僵尸进程

PS:

1.wait()函数是一个阻塞函数,等待回收子进程资源,如果没有子进程,wait返回-1
2.waitpid()函数则是一个非阻塞函数

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


int main()
{
    
    pid_t pid;
    pid = fork();

    if (pid > 0) {
        while (1) {
            printf("I am parent process\n");
            printf("wait for child: %d\n", wait(NULL));
            sleep(1);
        }
    } else if (pid ==0) {
        printf("I am child process\n");
        printf("My pid is: %d\n", getpid());
        sleep(10);
    } else {
        perror("fork");
    }
    
    return 0;
}

运行结果:

I am parent process
I am child process
My pid is: 5308
wait for child: 5308
I am parent process
wait for child: -1
I am parent process
wait for child: -1
I am parent process
wait for child: -1
I am parent process
wait for child: -1
I am parent process
wait for child: -1
I am parent process
wait for child: -1

◆ waitpid()

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


< -1 回收指定进程组内的任意子进程
-1 回收任意子进程
0 回收和当前调用waitpid一个组的所有子进程
> 0 回收指定ID的子进程

WNOHANG 如果没有子进程退出立即返回,这样就实现了非阻塞的wait

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


int main()
{
    pid_t pid;
    pid = fork();
    
    if (pid > 0) {
        while (1) {
            printf("I am parent process\n");
            pid_t pid_c = waitpid(0, NULL, WNOHANG);
            printf("go to next...\n");
        }    
    
    } else if (pid == 0) {
        printf("I am child process\n");
        sleep(10);
    } else {
        perror("fork");
    }
    return 0;
}

运行结果:

I am parent process
go to next...
I am parent process
go to next...
I am parent process
go to next...
I am parent process
go to next...
I am parent process
go to next...
I am parent process
go to next...
I am parent process
go to next...
I am parent process
go to next...

 

posted @ 2017-11-24 22:08  夜行过客  阅读(250)  评论(0编辑  收藏  举报