【进程创建】

目录

进程创建的方式

1.在操作系统上输入的指令。

2.已经启动的软件。

3.程序员在代码层面上调用系统调用创建进程。

linux中第一个创建的进程是init,操作系统以后的进程创建,就可以依靠该init进程为父进程创建子进程,创建的子进程也可以做为之后进程创建的父进程。所以进程的创建是依靠父进程创建出来的。在使用linux命令行解释器执行指令创建进程中,命令行解释器bash就是父进程。

查看进程pid

top指令查看进程id

也可以ps axj | grep name查看某个名字的进程id

也可以使用系统调用getpid()获取当前运行进程的pid

ls /proc/id -l 查看进程当前目录等信息

每个进程都有自己的id编号pid,所以操作系统管理进程时,就可以找该进程对应的pid编号。

调用系统调用创建子进程

fork()是linux创建子进程的系统调用,返回值是整形,如果返回值为0,就是子进程,如果返回值大于0(父进程创建子进程的子进程pid),就是父进程,如果返回值小于0,创建子进程失败,返回值为-1,错误码被设置。

查看父进程可以调用getppid(),当程序被运行的时候,我们发现两个循环体尽然都有在执行,而且他们的进程pid都不一样,但是子进程的ppid和父进程的pid一样,说明子进程是由父进程创建的。这段代码看着好像只有一个执行流,但是有两个进程。他们在并行地运行,执行。进程的概念给上层用户提高了一个很好的假象,每个程序独自占用处理器的资源,独自占用一个内存资源。

fock函数做了的工作

  1. fork函数在已有的进程中创建了新的进程,即父进程创建了子进程。所以有两个返回值。
  2. fork创建成功返回的两个返回值,一个是父进程的调用fork时返回的,一个是子进程的创建的时候返回的。
  3. fork返回值给父进程为子进程pid,因为一个父进程可以创建多个子进程,父进程实际上要对子进程管理。fork给子进程返回值为0,因为子进程只有一个父进程。

子进程刚开始创建的状态

c 复制代码
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
    int pid = fork();
    printf("I am father process,my pid is: %d, my praent ppid is: %d#########\n", getpid(), getppid());
    printf("I am running: pid :%d   ppid:%d\n",getpid(),getppid());
    if (pid == 0)
    {
        while (1)
        {
            printf("I am child process,my pid is: %d, my praent ppid is: %d\n", getpid(), getppid());
            sleep(1);
        }
    }
    if (pid > 0)
    {
        while (1)
        {
            printf("I am father process,my pid is: %d, my Ppraent ppid is: %d\n", getpid(), getppid());
            sleep(1);
        }
    }
    return 0;
}

子进程创建的时候,是根据父进程为模板创建的,和父进程的代码和数据,内存共享的。创建的子进程连接到运行队列里。因为子进程是根据父进程为模板创建的,继承了父进程的代码和数据。可以看出在fork成功后,子进程也是可以看到fork之前的代码的。

一个变量,两个不同的值

父进程创建子进程后。代码和数据共享指向的内存空间也是一样的。如果有一个全局的变量,父子进程对这个进程操作不同。数据发送了改变,哪个进程先对这个数据改变,操作系统就会申请新的内存给该进程,这是为了保证进程的独立性,互补干扰,让进程有独自的存放空间。代码的全局变量num在不同的进程中,指向不同的指令,一个自增,一个自减,互补干扰。观察到对同一变量num取地址,发现一样,其实这个地址是虚拟地址,并不是真实的物理地址。父子进程对数据改变的话,真实物理地址就会不一样。

c 复制代码
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdbool.h>
static num = 100;
int main()
{
    int pid = fork();
    printf("I am father process,my pid is: %d, my praent ppid is: %d#########\n", getpid(), getppid());
    printf("I am running: pid :%d   ppid:%d\n",getpid(),getppid());
    if (pid == 0)
    {
        while (true)
        {
            printf("I am child process,my pid is: %d, my praent ppid is: %d\n", getpid(), getppid());
            printf("num = %d,num address: %p\n",num++,&num);
            printf("#######################################\n");
            sleep(1);
        }
    }
    if (pid > 0)
    {
        while (true)
        {
            printf("I am father process,my pid is: %d, my Ppraent ppid is: %d\n", getpid(), getppid());
            printf("num = %d,num address: %p\n",num--,&num);
            printf("#######################################\n");
            sleep(1);
        }
    }
    return 0;
}

创建子进程的作用

创建子进程本质上是为了和父进程执行不同的任务。所以创建子进程后,一般就会指向新重新加载到内存的代码和数据。

相关推荐
且从容.26 分钟前
Ubuntu安装flume
linux·ubuntu·flume
承渊政道1 小时前
Linux网络学习【Reactor反应堆模式】
linux·网络·学习·ubuntu·reactor
且从容.4 小时前
ubuntu安装flink
linux·ubuntu·flink
爱和冰阔落5 小时前
【Linux网络】TCP 服务器如何并发处理多个客户端?从 fork、僵尸进程到双重 fork
linux·运维·服务器·网络
程序员沉梦听雨5 小时前
WSL2的安装与使用
linux·wsl
微小的鱼5 小时前
Linux的渲染与显示系统链路
android·java·linux
lisanmengmeng6 小时前
alertmanger 标签 rules 打上分组标签
linux·运维·服务器
Android系统攻城狮7 小时前
Linux FFmpeg深度解析之av_write_frame调用流程与实战(三十三)
linux·运维·服务器·ffmpeg·音视频进阶·ffmpeg音视频
Linux-lucky18 小时前
45-Linux学习之旅之防火墙与WEB加固
linux·前端·网络·学习·ubuntu
禁默18 小时前
启元 Q1 二次开发实践:Ubuntu 部署与仿真验证,从 PrimeConsole 到 ROS 2 Humble + RViz
linux·运维·ubuntu