您的位置:首页 > 科技 > IT业 > 工作有效性_手工外包加工网可信吗_互联网平台推广是什么意思_数据网站

工作有效性_手工外包加工网可信吗_互联网平台推广是什么意思_数据网站

2024/12/26 14:16:01 来源:https://blog.csdn.net/m0_74506452/article/details/144058953  浏览:    关键词:工作有效性_手工外包加工网可信吗_互联网平台推广是什么意思_数据网站
工作有效性_手工外包加工网可信吗_互联网平台推广是什么意思_数据网站

子进程

什么是子进程?

子进程指的是由一个已经存在的进程(称为父进程或父进程)创建的进程.

如: OS (操作系统) 就可以当作是一个进程, 用来管理软硬件资源, 当我点击浏览器, 想让浏览器运行起来时, 实际上是由 OS 接收指令, 然后 OS 帮我们将浏览器运行起来, 浏览器就是一个子进程, 是由 OS 创建出来的进程, 所以 OS 就是浏览器这个进程的父进程.
( OS 并不是一个单独的进程, 是由多个进程和线程组成的复杂结构, 这里为了方便理解, 将整个 OS 当作是一个进程)

如何创建子进程

在 Linux 中, 操作系统为我们提供了一个系统调用函数: fork()

fork() 函数可以在程序中, 创建一个子进程.

#include <sys/types.h>
#include <unistd.h>
// 以上为所需的库函数// 函数声明
pid_t fork(void);

可以看到这个函数没有参数, 有一个 pid_t 类型的返回值.

成功后, 子进程的PID将在父进程中返回, 0将在子进程中返回.

失败时, -1在父进程中返回, 不创建子进程, 并且适当设置了errno.

#include <iostream>
#include <unistd.h>
#include <sys/types.h>int main()
{pid_t pid = fork();if(pid == -1){std::cout << "fork error" << std::endl;}if(pid == 0){std::cout << pid << ": this is child" << std::endl;}else{std::cout << "创建的子进程的pid: " << pid << std::endl;}return 0;
}

可以看到程序运行之后, 打印出了两条语句.
创建出来的子进程的 pid 是 598281.

但是我们只是看到了有进程被创建了, 怎么证明他们之间是父子关系?

先来介绍两个函数: 

#include <sys/types.h>
#include <unistd.h>pid_t getpid(void); // 返回当前进程的 pid
pid_t getppid(void); // 返回当前进程的 父进程的 pid

然后将上面的代码修改一下

#include <iostream>
#include <unistd.h>
#include <sys/types.h>int main()
{pid_t pid = fork();if(pid == -1){std::cout << "fork error" << std::endl;}if(pid == 0){std::cout << "this is child ppid: " << getppid() << " pid: " << getpid() << std::endl;}else{std::cout << "this is parent pid: " << getpid() << std::endl;}return 0;
}

 

可以观察到子进程打印出来的父进程的pid, 和父进程的 pid 是相同的, 所以他们之间确实是父子关系.

fork 函数讲解 一

从上面的代码我们可以感知到, 子进程所执行的代码, 是 fork 函数之后的代码.
否者子进程也从头开始执行, 那么就形成了一个死循环, 子进程还回去创建自己的进程.
就会创建出无数的进程, 最后软件资源也就被分配完了, 电脑也可以关机重启了.

那么 fork 函数有什么作用呢?

#include <iostream>
#include <unistd.h>
#include <sys/types.h>int main()
{pid_t pid = fork();if(pid == -1){std::cout << "fork error" << std::endl;}if(pid == 0){// 执行子进程的专有代码}else{// 执行父进程的专有代码}return 0;
}

比如: 我在使用 QQ 聊天, 此时有人发了一个文件给我, 我点击接收文件, 然后 QQ 就创建了一个子进程去执行文件的下载, 这样在文件下载的时候, 我还是能聊天. 

#include <iostream>
#include <unistd.h>
#include <sys/types.h>int main()
{pid_t pid = fork();if (pid == -1){std::cout << "fork error" << std::endl;}if (pid == 0){while (1){std::cout << "我在聊天" << std::endl;}}else{while (1){std::cout << "我在下载东西" << std::endl;}}return 0;
}

fork 函数讲解 二

那么 fork 函数究竟是怎么创建出子进程的?

fork 函数创建的子进程, 实际上是一个父进程的副本, 子进程中没有代码和数据, 子进程和父进程共享代码和数据

所以 fork 之后父子进程执行的代码是一样的.

那么问题来了, 在上面创建子进程的代码中, 我们通过 fork 的返回值 pid 来区分父子进程.

#include <iostream>
#include <unistd.h>
#include <sys/types.h>int main()
{pid_t pid = fork();if(pid == -1){std::cout << "fork error" << std::endl;}if(pid == 0){// 执行子进程的专有代码}else{// 执行父进程的专有代码}return 0;
}

我们又说父子进程之间是共享代码和数据的, 那么 pid 这个变量也是两方共享的, pid 是一个变量, 一个变量怎么可能同时存在多个值.

fork 函数讲解 三

(1) 两个值从哪来

首先我们要知道, 这两个值是从哪里来的?

之前说了, 父子进程都会执行 fork 函数之后的内容. 
当 fork 函数执行到 return 时, fork 函数才算结束.

那么我们可以看到, 在 fork 函数执行 return 之前, 子进程已经被创建, 并且运行起来了.
之前所说的 子进程 执行 fork 函数之后的代码, 是不准确的,
在 fork 的内部还有一部分代码子进程是会执行的, 从放入调度队列之后.

那么也就是说, 父子进程都是执行 fork 的 return 函数, 那么 return 函数就被执行了两次, 那么也就出现了两个返回值.

(2) 一个变量怎么有多个值

我们已经知道了两个值是怎么来的.
那么下一个问题: 为什么 pid 会有两个值?

之前我们说过了, 父子进程共享数据, 那么父子进程访问同一个变量, 得到的值应该是相同的.

首先我们需要知道: 进程之间具有独立性, 进程有自己的堆栈, 数据 .......
在上面我们说了, 父子进程之间共享数据, 那么当父子进程运行之后, 可能就会修改数据
那么无论哪一方修改数据, 对另一个进程而言, 它的独立性都遭到了破坏. 这是不合理的.

所以, 为什么在创建子进程的时候, 父子进程共享代码和数据?

因为: 拷贝数据需要消耗资源, 而父子进程在运行时, 可能都不会发生修改数据的操作.

那么我就在父子进程修改数据之前, 让父子进程共享,

如果有进程发生了修改数据的操作, 此时我们在将父子进程的数据分离开来. (写时拷贝)

父子进程各自有一份独立的数据 ,各自维护

fork 函数的返回值, 赋值给 pid 时, 也就是发生了数据的修改, 那么此时就会发生写时拷贝, 将父子进程之间的资源分离开, 各自维护各自的数据.

所以当我们在父子进程使用同一个对象时, 获取的 值 不同也就可以理解了.
pid 看上去时一个变量, 实际上是在父子进程中的 两个不同的变量, 只是在父子进程中名称相同.

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com