linux学习(进程管理)[8]

创建进程

myproc.c

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

int main()
{
	printf("我是父进程\n");
	
	pid_t id = fork();
	if(id < 0)
	{
		printf("创建子进程失败\n");
		return 1;
	}
	else if(id == 0)
	{
		while(1)
		{
			printf("我是子进程: pid: %d ,ppid: %d\n",getpid(),getppid());
			sleep(1);
		}
	}
	else
	{
		while(1)
		{
			printf("我是父进程: pid: %d ,ppid: %d\n",getpid(),getppid());
			sleep(1);
		}
 	}
}

子进程0,父进程1,失败-1
在这里插入图片描述
查看进程

ps axj | grep myproc

描述,fork创建子进程时,操作系统都做了什么

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
fork之后子进程和父进程共享全部代码,而不仅仅只有after后的

写时拷贝

在Linux中,fork()系统调用用于创建一个新的进程,新进程是原始进程(父进程)的副本。在fork()调用之后,父进程和子进程共享相同的内存映像,这包括代码段、数据段和堆栈。

在fork()调用之后,父进程和子进程之间使用写时拷贝(Copy-on-Write,COW)技术来减少内存开销。具体来说,当父进程或子进程尝试修改共享的内存页时,操作系统会为修改后的内存页创建一个新的副本,并使父进程和子进程指向各自的副本。

下面是一个示例,演示了父子进程的写时拷贝:

#include <iostream>
#include <unistd.h>

int main() {
    int data = 100;

    pid_t pid = fork();

    if (pid == -1) {
        std::cerr << "fork() failed" << std::endl;
        return 1;
    } else if (pid == 0) {
        // 子进程
        std::cout << "Child process: data = " << data << std::endl;
        data = 200;
        std::cout << "Child process: modified data = " << data << std::endl;
    } else {
        // 父进程
        std::cout << "Parent process: data = " << data << std::endl;
        data = 300;
        std::cout << "Parent process: modified data = " << data << std::endl;
    }

    return 0;
}

在上述代码中,我们首先定义了一个整数变量data,并初始化为100。然后,我们调用fork()系统调用创建一个新的进程。

在子进程中,我们输出data的值,然后将其修改为200,并再次输出修改后的值。

在父进程中,我们也输出data的值,然后将其修改为300,并再次输出修改后的值。

运行上述代码,可能会得到如下输出:

Parent process: data = 100
Parent process: modified data = 300
Child process: data = 100
Child process: modified data = 200

可以看到,父子进程共享相同的data变量,但在修改时会进行写时拷贝,使得父进程和子进程拥有各自的副本。因此,父进程和子进程对data变量的修改互不影响。
延时申请技术
创建子进程,不需要将不会被访问的,或者只会读取的数据拷贝一份将来会被父进程或者子进程写入的数据才会拷贝但是一般而言os无法提前知道哪些空间可能会被写入,即使拷贝也不知拷贝时间
==所以os使用写时拷贝技术将父子进程的数据进行分离 ==
在这里插入图片描述

cpu怎么知道要执行什么指令||子进程为什么从after后执行

在这里插入图片描述

进程终止

  1. 操作系统所作:
    操作系统释放进程申请相关的内核数据结构和对应的数据和代码本质就是释放系统资源

  2. 进程终止的常见方式:
    a. 代码跑完,结果正确
    b.代码跑完,结果不正确 (main函数返回值的意义?return0 ?)
    c.代码没有跑完,程序崩溃了(信号部分)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. 用代码如何终止一个进程
    main函数的return语句就是用来终止进程的! return+退出码
    exit在代码的任何地方调用,都表示直接终止进程
    exit在退出时会将数据刷新到缓冲区 _exit不会

exit || _exit

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

进程等待

在这里插入图片描述
父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息

wait–基本验证,回收僵尸进程的问题

在这里插入图片描述
阻塞式等待
在Linux中,wait()waitpid()是用于进程等待的系统调用。

wait()系统调用用于让父进程等待其子进程的终止。当父进程调用wait()时,如果子进程已经终止,则wait()立即返回,并返回子进程的进程ID。如果子进程还未终止,则父进程会被阻塞,直到子进程终止。

waitpid()系统调用是wait()的一个变种,它允许父进程指定要等待的子进程的进程ID。此外,waitpid()还可以指定一些额外的选项,例如WNOHANG,使waitpid()在没有可等待的子进程时立即返回。

下面是一个示例,演示了wait()waitpid()的使用:

#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

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

    if (pid == -1) {
        std::cerr << "fork() failed" << std::endl;
        return 1;
    } else if (pid == 0) {
        // 子进程
        std::cout << "Child process: PID = " << getpid() << std::endl;
        sleep(2); // 子进程休眠2秒
        std::cout << "Child process: exiting" << std::endl;
        return 0;
    } else {
        // 父进程
        std::cout << "Parent process: PID = " << getpid() << std::endl;
        std::cout << "Parent process: waiting for child process to exit" << std::endl;

        // 等待子进程终止
        int status;
        pid_t terminated_pid = wait(&status);

        if (WIFEXITED(status)) {
            std::cout << "Parent process: child process " << terminated_pid << " exited normally with status " << WEXITSTATUS(status) << std::endl;
        } else if (WIFSIGNALED(status)) {
            std::cout << "Parent process: child process " << terminated_pid << " exited due to signal " << WTERMSIG(status) << std::endl;
        }
    }

    return 0;
}

在上述代码中,我们使用fork()创建了一个子进程。在子进程中,我们输出子进程的进程ID,然后休眠2秒钟,最后返回0。

在父进程中,我们输出父进程的进程ID,并使用wait()等待子进程终止。当子进程终止后,wait()返回子进程的进程ID,并将子进程的状态存储在status变量中。我们使用WIFEXITED()WEXITSTATUS()宏来检查子进程是否正常终止,并获取子进程的退出状态。

运行上述代码,可能会得到如下输出:

Parent process: PID = 1234
Parent process: waiting for child process to exit
Child process: PID = 1235
Child process: exiting
Parent process: child process 1235 exited normally with status 0

可以看到,父进程调用wait()等待子进程终止,并成功获取到子进程的退出状态。
在上述代码中,status是一个整数变量,用于存储子进程的终止状态。在wait()waitpid()返回时,可以通过检查status来获取子进程的退出状态。

status的类型是int,但它实际上是一个位字段,可以通过一些宏来解析它的值。下面是一些常用的宏:

  • WIFEXITED(status):如果子进程正常终止,则返回真。
  • WEXITSTATUS(status):如果WIFEXITED()为真,则返回子进程的退出状态。
  • WIFSIGNALED(status):如果子进程因为信号而终止,则返回真。
  • WTERMSIG(status):如果WIFSIGNALED()为真,则返回导致子进程终止的信号编号。

这些宏可以帮助我们解析status变量,以确定子进程的终止状态。

在上述示例代码中,我们使用了WIFEXITED()WEXITSTATUS()宏来检查子进程是否正常终止,并获取子进程的退出状态。如果子进程正常终止,WEXITSTATUS()将返回子进程的退出状态。

如果子进程因为信号而终止,我们可以使用WIFSIGNALED()WTERMSIG()宏来获取导致子进程终止的信号编号。

请注意,status中的位字段是由操作系统设置的,因此可以使用这些宏来解析status的值。

waitpid–获取子进程退出结果的问题

在这里插入图片描述
status不是按照整数来体现的
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值