Linux进程控制(1)

简介: Linux进程控制(1)

零、前言


前篇我们讲解学习了关于进程的概念知识,本章主要讲解关于进程的控制,深入学习进程


一、进程创建


1、fork函数


  • 概念:


在linux中fork函数从已存在进程中创建一个新进程(子进程),而原进程为父进程


  • fork函数原型:


pid_t fork(void);


注意:

使用fork()函数需要包含头文件<unistd.h>;pid_t类型需要包含头文件<sys/types.h>


fork成功后对子进程返回0,对父进程返回子进程id,fork出错返回-1


内核视角看待fork:

进程调用fork,内核分配新的内存块和内核数据结构给子进程


将父进程部分数据结构内容拷贝至子进程(例如PCB进程控制块,进程地址空间,页表等)


添加子进程到系统进程列表当中,当fork返回后开始调度器调度进程


示图:


fork后执行问题:

当一个进程调用fork之后,父子进程共享同一份代码,也就是说整个代码父子进程都可以看到,但是此时父子进程的执行位置都是相同的,也就是说fork返回后子进程也是往fork之后的代码执行(并非再从头执行)


示例:


#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
    printf("Before fork: pid is %d\n", getpid());
    pid_t pid=fork();
    if (pid== -1 )//fork错误
    {
    perror("fork fail");
        exit(1);
    }
    printf("After fork:pid is %d, fork return %d\n", getpid(), pid);
    sleep(1);
    return 0;
}


结果:


示图:


2、fork返回值


返回值:

fork成功对子进程返回0,对父进程返回子进程的pid


写时拷贝


概念:

fork成功之后父子代码共享,当父子不写入数据时,数据也是共享的,当任意一方试图写入,便以写时拷贝的方式各自一份副本


为什么数据要进行写时拷贝:

进程具有独立性,多进程运行,需要独享各种资源,多进程运行期间互不干扰,不能让子进程的修改影响到父进程


为什么不在创建子进程的时候就进行数据的拷贝:

子进程不一定会使用父进程的所有数据,并且在子进程不对数据进行写入的情况下,没有必要对数据进行拷贝,我们应该按需分配,在需要修改数据的时候再分配(延时分配),这样可以高效的使用内存空间,提高fork效率,以及fork的成功率


代码会不会进行写时拷贝:

90%的情况下是不会的,但这并不代表代码不能进行写时拷贝,例如在进行进程替换的时候,则需要进行代码的写时拷贝


示图:


fork函数为什么要给子进程返回0,给父进程返回子进程的PID:


一个父进程可以创建多个子进程,而一个子进程只能有一个父进程。因此,对于子进程来说,父进程是不需要被标识的;而对于父进程来说,子进程是需要被标识的,因为父进程创建子进程的目的是让其执行任务的,父进程只有知道了子进程的PID才能很好的对该子进程进行深入操作


为什么fork存在“两个”返回值:


父进程创建子进程时,子进程以父进程为模板构建进程,代码数据父子共享,返回时也是父子进程进行修改数据时,由页表发现该数据是父子进程共享的,所以系统会找到另一个物理空间进行拷贝数据,拷贝数据后再修改数据,达到数据各有一份互不干扰的目的,保证进程的独立性

3、fork用法


我们创建子进程并不是为了父进程执行一样的代码,而是为了使父子进程同时执行不同的代码段


例如:父进程等待客户端请求,生成子进程来处理请求


#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
int main()
{
    pid_t id=fork();//创建子进程
    if(id==0)
    {
        //child
        int cnt=0;
        while(1)
        {
            printf("I am child: pid:%d ppid:%d\n",getpid(),getppid());
            sleep(1);
            if(cnt==8)
                break;
            cnt++;
        }   
        exit(1);//终止进程
    }
    else if(id>0)
    {
        //father
       int cnt=0;
        while(1)
        {
            printf("I am father: pid:%d ppid:%d\n",getpid(),getppid());
            sleep(1);
            if(cnt==8)
                break;
            cnt++;
        }   
    }
    return 0;
}


image.png


  • 用法2:fork返回后调用exec函数替换进程


注:在下文有着重讲解


4、fork失败


fork本质就是向系统要资源,当某个资源不够时则会发生fork失败


  • 失败原因:


1.系统中有太多的进程



2.实际用户的进程数超过了限制



用法1:fork返回后分流执行不同代码


示例:


相关文章
|
2天前
|
NoSQL Linux 程序员
【linux进程信号(一)】信号的概念以及产生信号的方式
【linux进程信号(一)】信号的概念以及产生信号的方式
|
2天前
|
Linux
【linux进程间通信(一)】匿名管道和命名管道
【linux进程间通信(一)】匿名管道和命名管道
|
2天前
|
Java Shell Linux
【linux进程控制(三)】进程程序替换--如何自己实现一个bash解释器?
【linux进程控制(三)】进程程序替换--如何自己实现一个bash解释器?
|
2天前
|
算法 Linux Shell
【linux进程(二)】如何创建子进程?--fork函数深度剖析
【linux进程(二)】如何创建子进程?--fork函数深度剖析
|
2天前
|
存储 Linux Shell
【linux进程(一)】深入理解进程概念--什么是进程?PCB的底层是什么?
【linux进程(一)】深入理解进程概念--什么是进程?PCB的底层是什么?
|
3天前
|
消息中间件 Unix Linux
Linux的学习之路:17、进程间通信(1)
Linux的学习之路:17、进程间通信(1)
18 1
|
3天前
|
存储 安全 Linux
Linux的学习之路:9、冯诺依曼与进程(1)
Linux的学习之路:9、冯诺依曼与进程(1)
18 0
|
8天前
|
算法 Linux 调度
深入理解Linux内核的进程调度机制
【4月更文挑战第17天】在多任务操作系统中,进程调度是核心功能之一,它决定了处理机资源的分配。本文旨在剖析Linux操作系统内核的进程调度机制,详细讨论其调度策略、调度算法及实现原理,并探讨了其对系统性能的影响。通过分析CFS(完全公平调度器)和实时调度策略,揭示了Linux如何在保证响应速度与公平性之间取得平衡。文章还将评估最新的调度技术趋势,如容器化和云计算环境下的调度优化。
|
10天前
|
监控 Linux
linux监控指定进程
请注意,以上步骤提供了一种基本的方式来监控指定进程。根据你的需求,你可以选择使用不同的工具和参数来获取更详细的进程信息。
14 0
|
11天前
|
消息中间件 监控 Linux
Linux进程和计划任务管理
通过这些命令和工具,你可以有效地管理Linux系统中的进程和计划任务,监控系统的运行状态并保持系统的稳定和可靠性。 买CN2云服务器,免备案服务器,高防服务器,就选蓝易云。百度搜索:蓝易云
102 2