体验进程的生命周期

体验进程的生命周期

通过调用fork(),exec,wait(), sleep(),exit()等系统调用,编写代码,体验进程创建到结束的整个过程。

函数详解

fork()

fork() 函数会新生成一个进程,调用 fork 函数的进程为父进程,新生成的进程为子进程。在父进程中返回子进程的 pid,在子进程中返回 0,失败返回-1
请添加图片描述
一个进程调用fork()函数后,系统先给新的进程分配资源。然后把原来的进程的所有值都复制到新的新进程中,相当于克隆了一个自己。

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
void do_something(long t)
{
    int i=0;
    for(i=0;i<t;i++)
        for(i=0;i<t;i++)
            for(i=0;i<t;i++)
               ;
}
int main(){
    pid_t pid;
    printf("PID before fork():%d\n",getpid());
    //getpid()获取当前进程的进程ID
    pid=fork();
    //fork 父进程返回>0 子进程返回0

    pid_t npid=getpid();
    //获取当前进程的pid
    if(pid<0)//fork失败
        perror("fork error\n");
    else if(pid==0)//子进程
    {
        while(1)
        {
            printf("I am child process,PID is %d\n",npid);//打印对应npid
            do_something(1000000000);
        }
    }
    else if(pid>0)//父进程
    {
        while(1)
        {
            printf("I am father process,PID is %d\n",npid);//打印对应npid
            do_something(1000000000);
        }
    }

}

在这里插入图片描述
可以看到其顺序是不规则的,即两个进程并发执行
在这里插入图片描述
exec

exec函数族的作用是根据指定的文件名找到可执行文件

使用exec函数族主要有两种情况:

(1)当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用exec函数族中的任意一个函数让自己重生。

(2)如果一个进程想执行另一个程序,那么它就可以调用fork函数新建一个进程,然后调用exec函数族中的任意一个函数,这样看起来就像通过执行应用程序而产生了一个新进程

if(fork()!=0)
{
    //parent code
    wait(NULL);
}
else
{
    //children code
	exec(command,parameters,0);
}

wait()

wait() 是一个系统调用,用于使父进程等待子进程的终止,并获取子进程的退出状态。如果他找到了一个已经变成僵尸的子进程,wait就会收集这个子进程的信息并释放其PCB,没有找到时则一直等待。

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

int main(){
    pid_t pc,pr;
    pc=fork();
    if(pc<0)
    {
        printf("error ocurred!\n");
    }
    else if(pc==0)
    {
        printf("This is child process with pid of %d\n",getpid());
        sleep(10);
    }
    else{
        pr=wait(NULL);
        printf("I catched a child process with pid of %d\n",pr);
    }
    exit(0);
}

在这里插入图片描述
某些时候父进程要等待子进程执行结束后才能继续运行,或者子进程的功能是为父进程提供了下一步执行的先决条件,这时需要进程间的同步,就是要协调好进程,使之以安排好的次序依次执行

sleep()

sleep函数可以使计算机程序(进程,任务或线程)进入休眠,使其在一段时间内处于非活动状态。当函数设定的计时器到期,或者接收到信号、程序发生中断都会导致程序继续执行。

exit()

用来终止进程,执行对应的内核函数do_exit(),该函数回收与进程相关的各种内核数据结构,把进程的状态设为TASK_ZOMBIE,并把其所有的子进程都托付给init进程,最后调用schedule()函数,选择新的进程执行。

使用exit后,进程不会立即消失,而是变为僵尸状态,等待父进程的wait进行回收。

代码示例

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

int main(){
    pid_t pid,pc;//定义一个pid结构体,pid_t在task_struct下;
    char command;
    char *arg_ps_tree[]={"pstree",NULL};//shell 中pstree;
    char *arg_ps_ef[]={"ps","-ef",NULL};//shell中ps -ef;
    char *arg_ps_a[]={"ps","-a",NULL};//shell中ps -a;
    char *arg_ps_x[]={"ps","-x",NULL};//shell中ps -x;
    char *envp[]={0,NULL};

    while(1){
        printf("**********************************\n");
        printf("输入ps相关命令,来查看进程相关信息\n");
        printf("输入t执行'pstree'命令\n");
        printf("输入e执行'ps -ef'命令\n");
        printf("输入a执行'ps -a'命令\n");
        printf("输入x执行'ps -x'命令\n");
        printf("输入q退出\n");
        command = getchar();//获取命令;
        getchar();//回车;

        pid = fork();//创建子进程;
        if(pid<0) {
            perror("Error!");//创建子进程失败;
            return -1;
        }
        else if(pid==0){//子进程;
            printf("This is the child process with pid of %d\n",getpid());
            switch(command){
                case 't':
                execve("/bin/pstree",arg_ps_tree,envp);
                break;
                case 'e':
                execve("/bin/ps",arg_ps_ef,envp);
                break;
                case 'a':
                execve("/bin/ps",arg_ps_a,envp);
                break;
                case 'x':
                execve("/bin/ps",arg_ps_x,envp);
                break;
                case 'q':
                break;
                default:
                    perror("wrong command:\n");
                break;//子进程结束;
            }
            exit(0);//子进程进入僵尸状态;
        }
        else{//父进程
            pc=wait(NULL);
            sleep(30);
            printf("This is father process with pid of %d\n",getpid());
            if(command == 'q') break;
            printf("I catched a child process with pid of %d\n",pc);
        }
    }
    return 0;
}

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

int main() {
    pid_t child_pid;
    int status;

    // 创建一个子进程
    child_pid = fork();

    if (child_pid == -1) {
        perror("Fork failed");
        exit(1);
    }

    if (child_pid == 0) {
        // 子进程的代码
        printf("这是子进程,进程ID:%d\n", getpid());

        // 使用 exec 函数来运行另一个程序
        char *args[] = {"ls", "-l", NULL};
        execvp("ls", args);

        // 如果 exec 函数执行失败,打印错误信息
        perror("Exec failed");
        exit(1);
    } else {
        // 父进程的代码
        printf("这是父进程,子进程的进程ID:%d\n", child_pid);

        // 使用 wait 函数等待子进程的结束
        wait(&status);
        if (WIFEXITED(status)) {
            printf("子进程正常结束,退出状态:%d\n", WEXITSTATUS(status));
        } else {
            printf("子进程异常结束\n");
        }

        // 父进程休眠一段时间
        sleep(2);

        printf("父进程结束\n");
    }

    return 0;
}

结果展示

test

ps -a

在这里插入图片描述
ps -x

在这里插入图片描述
ps -ef|more
在这里插入图片描述
pstree
在这里插入图片描述
test1
请添加图片描述

心得体会

​ 通过使用 fork(), exec(), wait(), sleep(), 和 exit() 等系统调用,我深刻理解了进程创建和管理的基本原理。父进程可以通过 fork() 创建子进程,并可以使用 wait() 等待子进程的结束,以获取其退出状态。子进程可以通过 exec() 执行其他程序,并替换自己的代码和数据。此外,sleep() 可用于进程的暂停,exit() 可用于正常或异常退出进程。示例代码也能够很好的展示了进程创建到结束的完整生命周期,有助于深入地理解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值