首页 > 其他分享 >第三章学习总结

第三章学习总结

时间:2022-10-09 21:35:02浏览次数:54  
标签:总结 fork 第三章 int pid 学习 getpid printf 进程

第3章 Unix/Linux进程管理

1 知识点归纳

1.1 多任务处理

一般来说,多任务处理指的是同时进行几项独活动的能力。在计算机技术中,多任务处理指的是同时执行几个独立的任务。多任务处理是通过在不同任务之间多路复用CPU的执行时间来实现的,即将CPU执行任务从一个任务切换到另一个任务。

1.2 进程的概念

进程的正式定义:进程是对映像的执行。

一个简单的PROC结构体:

typedef struct proc{
    struct proc *next;	 // next proc pointer
    int *ksp; 			 // saved sp: at byte offset 4
    int pid; 			 // process ID                          
    int ppid; 			 // parent process pid     
    int status; 		 // PROC status=FREE|READY, etc.  
    int priority; 		 // scheduling priority  
    int kstack[1024]; 	 // process execution stack  
}PROC;

在PROC结构体中:

  • next是指向下一个PROC结构体的指针,用于在各种动态数据结构(如链表和队列)中维护PROC结构体。ksp字段是保存的堆栈指针。
  • pid是标识一个进程的ID编号,
  • ppid是父进程ID的编号,
  • status是进程的当前状态,
  • priority是进程调度优先级,
  • kstack是进程执行的堆栈。

1.3 Unix/Linux中的进程

1.3.1 进程来源

操作系统启动时,内核会强制创建一个PID=0的初始进程,即通过分配PROC结构体(通常是PROC[0])进行创建,初始化PROC内容,并让运行指向proc[0];系统执行初始化进程P0;大多数操作系统都以这种方式开始第一个进程。P0继续初始化系统,包括系统硬件和内核数据结构。然后,它挂载一个根文件系统,使系统可以使用文件。初始化系统后,P0复刻出一个子进程P1,并把进程切换为以用户模式运行P1。

1.3.2 INIT和守护进程

当进程P1开始运行时,它将其执行镜像改为INIT程序。因此,P1通常被称为INIT进程,因为它的执行映像是init程序。P1开始复刻出许多子进程。P1的大部分子进程都是用来提供系统服务的。它们在后台运行,不与任何用户交互。这样的进程称为守护进程。守护进程的例子有:

syslogd :log daemon process
inetd  	:Internet service daemon process
httpd 	:HTTP server daemon process
etc.
1.3.3 登录进程

除了守护进程之外,P1还复刻了许多LOGIN进程,每个终端上一个,用于用户登录。每个LOGIN进程打开三个与自己的终端相关联的文件流,这三个文件流是用于标准输入的stdin、用于标准输出的stdout和用于标准错误消息的stderr。每个文件流都是指向进程堆区中FILE结构体的指针。每个FILE结构体记录一个一个文件描述符(数字),stdin的文件描述符是0,stdout的是1,stderr的是2。然后,每个LOGIN进程向stdout显示一个

login:

以等待用户登录。

1.3.4 sh进程

当用户成功登录时,LOGIN进程会获取用户的gid和uid,从而成为用户的进程。它将目录更改为用户的主目录并列执行出的程序,通常是命令解释程序sh。现在,用户进程执行sh,因此用户进程通常称为sh进程。

1.3.5 进程的执行模式

Unix/Linux中,进程以两种不同的模式执行,即内核模式和用户模式,简称Kmode和Umode。如图3.4所示。

在进程的生命周期中,会在Kmode和Umode之间发生多次迁移。每个进程都在Kmode下产生并开始执行。事实上,它在Kmode下执行所有相关操作,包括终止。在Kmode下通过将CPU状态寄存器从K模式更改为U模式,可以轻松切换到Umode。但是进入Umode就不能够随意更改CPU状态了。Umode进程只能通过下面三种方式进入Kmode:

  1. 中断:外部设备发送给CPU信号,请求CPU服务。当在Umode下执行时,CPU中断是启用的,因此它将响应任何中断。中断发生时,CPU将进入Kmode处理中断,这将导致进程进入Kmode;
  2. 陷阱:陷阱是错误条件,错误条件被CPU识别为异常,使得CPU进入Kmode来处理错误。在Unix/Linux中内核陷阱处理程序将陷阱原因转换为信号编号,并将信号传递给进程。对于大多数信号,进程的默认操作是终止。
  3. 系统调用(syscall):允许Umode进程进入Kmode以执行内核函数的机制。当某进程执行完内核函数后,它将期望结果和一个返回值返回到Umode,0表示成功,1表示错误。发生错误,外部全局变量errno(在errno.h中)会包含一个ERROR代码,用于标识错误。

1.4 进程管理的系统调用

在本节中,我们将讨论Linux中与进程管理相关的以下系统调用:

fork(),wait(),exec(),exit()

每个都是发出时间系统调用的库函数:

int syscall(int a,int b,int c,int d);

其中,第一个参数a表示系统调用号,b、c、d表示对应核函数的参数。

1.4.1 fork()函数
Usage: int pid = fork();

fork()创建子进程并返回该子进程的Pid,如果fork()失败则返回-1。


#include <unistd.h>
#include <stdio.h>
 
int main ()
{
    pid_t fpid; 
	printf("this is %d my parent = %d\n", getpid(),getppid());
    fpid = fork();
    if (fpid < 0)
        printf("error in fork!");
    else if (fpid == 0)
    {
        printf("i am the child process, my process id is %d/n", getpid());//返回调用进程的PID
    }
    else
    {
        printf("i am the parent process, my process id is %d/n", getpid());//返回调用进程的PID
    }
    return 0;
}
1.4.2 进程执行顺序

在fork()完成后,子进程与父进程和系统中所有其他进程竞争CPU运行时间。接下来运行哪个进程取决于它们的调度优先级,优先级呈动态变化。
下面的示例演示了进程可能的各种执行顺序。

#include <stdio.h>
int main()
{
    int pid=fork(); // fork a child
    if (pid)
    {
        printf("PARENT %d CHILD=%d\n", getpid(), pid);
        //sleep(1);
        printf("PARENT %d EXIT\n", getpid());
    }  
        
    else
    {   
        printf("child %d start my parent«%d\n", getpid(), getppid());
        // sleep(2);    // sleep 2 seconds -> let parent die first
        printf("child %d exit my parent=%d\n", getpid(), getppid());
    }
}
1.4.3 等待子程序终止

在任何一个时候,一个进程都可以使用

int pid = wait(int *status);

系统调用,等待僵尸子进程。如果成功,则wait()会返回僵尸子进程的PID,而且status包含僵尸子进程的的exitCode()。此外,wait()还会释放僵尸子进程,以供重新使用。

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int pid, status;
    pid = fork();
    if (pid)
    {
        printf("PARENT %d WAITS FOR CHILD %d TO DIE\n", getpid(),pid); 
        pid = wait(&status);    // wait for ZOMBIE child process
        printf("DEAD CHILD=%d, status=0x%04x\n", pid, status);
    } // PARENT:
    else
    {
        printf("child %d dies by exit(VALUE)\n", getpid());
        exit(100);
    }
}
1.4.4 Linux中的subreaper进程

自内核3.4版本以来,Linux处理孤儿进程的方式略有不同。进程可以用系统调用将自己定义为subreaper进程:

prctl(PR_SET_SUBREAPER);

这样,init进程P1将不再是孤儿进程的父进程。
下面程序演示了Linux中的sub'reaper进程。

#include <stdio.h>
#include <unistd.h>
#include <wait.h>
#include <sys/prctl.h>
int main()
{
    int pid,r,status;
    printf("mark process %d as a subreaper\n",getpid());
    r = prctl(PR_SET_CHILD_SUBREAPER);
    pid = fork();
    if(pid)
    {
         printf("subreaper %d child = %d\n", getpid(), pid);
        while (1)
        {
             pid = wait(&status);
            if (pid > 0)
            {
                printf("subreaper %d waited a ZOMBIE=%d\n",getpid(), pid);}
                else
                     break;
            
        }
    }
    else
    {
        printf("child %d parent = %d\n", getpid(), (pid_t)getppid);
        pid = fork();
        if (pid)
        {
            printf("child=%d start: grandchild=%d\n", getpid(),pid);
            printf("child=%d EXIT: grandchild=%d\n",getpid(),pid);
        }
        else
        {
            printf("grandchild=%d start:myparent=%d\n",getpid(),getppid());
            printf("grandcild=%d EXIT:myparent=%d\n", getpid(),getppid());
        }
    }
}

2 实践内容与截图

2.1 fork()实践


代码:

#include <unistd.h>
#include <stdio.h>
 
int main ()
{
    pid_t fpid; 
	printf("this is %d my parent = %d\n", getpid(),getppid());
    fpid = fork();
    if (fpid < 0)
        printf("error in fork!");
    else if (fpid == 0)
    {
        printf("i am the child process, my process id is %d/n", getpid());//返回调用进程的PID
    }
    else
    {
        printf("i am the parent process, my process id is %d/n", getpid());//返回调用进程的PID
    }
    return 0;
}

2.2 进程执行顺序演示

代码:

#include <stdio.h>
int main()
{
    int pid=fork(); // fork a child
    if (pid)
    {
        printf("PARENT %d CHILD=%d\n", getpid(), pid);
        //sleep(1);
        printf("PARENT %d EXIT\n", getpid());
    }  
        
    else
    {   
        printf("child %d start my parent«%d\n", getpid(), getppid());
        // sleep(2);    // sleep 2 seconds -> let parent die first
        printf("child %d exit my parent=%d\n", getpid(), getppid());
    }
}

取消第(1)行注释,子进程先运行完成:

只取消第(2)行注释,子进程的ppiid改为其他PID号

2.3 等待和退出系统调用

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int pid, status;
    pid = fork();
    if (pid)
    {
        printf("PARENT %d WAITS FOR CHILD %d TO DIE\n", getpid(),pid); 
        pid = wait(&status);    // wait for ZOMBIE child process
        printf("DEAD CHILD=%d, status=0x%04x\n", pid, status);
    } // PARENT:
    else
    {
        printf("child %d dies by exit(VALUE)\n", getpid());
        exit(100);
    }
}

2.4 Linux中的subreaper进程

#include <stdio.h>
#include <unistd.h>
#include <wait.h>
#include <sys/prctl.h>
int main()
{
    int pid,r,status;
    printf("mark process %d as a subreaper\n",getpid());
    r = prctl(PR_SET_CHILD_SUBREAPER);
    pid = fork();
    if(pid)
    {
         printf("subreaper %d child = %d\n", getpid(), pid);
        while (1)
        {
             pid = wait(&status);
            if (pid > 0)
            {
                printf("subreaper %d waited a ZOMBIE=%d\n",getpid(), pid);}
                else
                     break;
            
        }
    }
    else
    {
        printf("child %d parent = %d\n", getpid(), (pid_t)getppid);
        pid = fork();
        if (pid)
        {
            printf("child=%d start: grandchild=%d\n", getpid(),pid);
            printf("child=%d EXIT: grandchild=%d\n",getpid(),pid);
        }
        else
        {
            printf("grandchild=%d start:myparent=%d\n",getpid(),getppid());
            printf("grandcild=%d EXIT:myparent=%d\n", getpid(),getppid());
        }
    }
}

3 总结

本章主要讨论了UNIX/LINUX进程管理,阐述了多任务处理原则,并使用实践了用于进程管理的系统调用,包括fork、wait、exec和exit;也实践了父进程与子进程的关系,包括进程终止和父进程等待操作之间关系的详细描述。

标签:总结,fork,第三章,int,pid,学习,getpid,printf,进程
From: https://www.cnblogs.com/yu15141310373/p/16773769.html

相关文章

  • 第三章学习笔记
    第三章Unix/Linux进程管理一、知识点归纳以及收获内容多任务处理该部分主要介绍了多任务处理的定义,多任务处理指的时同时进行几项独立活动的能力。多任务处理是通过......
  • 第三章
    一、学习笔记:二、遇到问题:对进程的产生存在疑问。三、解决方法:通过网上查询资料得知,现有的(父)进程复制自己的地址空间(fork)来创建一个新的(子)进程结构,每个新进程......
  • bootstrap入门学习笔记
    本来这记着一天的笔记,网上搜了一下教程手册,整理得比我的强多了。果断删掉。相应的bootStrap教程网址 ​​https://www.runoob.com/bootstrap/bootstrap-typography.html......
  • 【sqli-labs】学习--待续
    预备知识:数字型注入:这种sql语句中处理的是整型,不需要使用单引号来闭合变量的值。首先输入id=1',此时因为不是整型,sql语句会执行出错,抛出异常。然后输入id=1and1=1,此......
  • 20201322陈俊池学习笔记6
    20201322陈俊池学习笔记63.1多任务处理多任务处理指的是同时执行几个独立的任务。在单处理器(单CPU)系统中,一次只能执行一个任务。多任务处理是通过在不同任务之间......
  • drf学习笔记
    今日内容概要权限类使用频率类使用认证类源码分析权限类源码分析部分频率类源码分析鸭子类型今日内容详细权限类使用第一步:写一个类,继承BasePermission第......
  • KMP 算法 再次学习
    c++版后面再补packagecn.kbug.dynamic;importjava.util.Arrays;/***KMP算法本质上是对搜索的字符串做优化,然后在匹配的时候,能做到非常省时间*如果搜索的串......
  • 2022-2023-1 20221424 《计算机基础与程序设计》第6周学习总结
    2022-2023-120221424《计算机基础与程序设计》第6周学习总结作业信息这个作业属于哪个课程<班级的链接>(如2022-2023-1-计算机基础与程序设计)这个作业要求在哪......
  • 【SSM】学习笔记(一)—— Spring 概念、Spring IoC、Spring Bean相关知识、依赖注入、
    原视频:https://www.bilibili.com/video/BV1Fi4y1S7ix?p=1P1~P27目录一、Spring概述1.1、Spring家族1.2、Spring发展史1.3、SpringFramework系统架构图1.4、......
  • 2022-2023-1 20221313《计算机基础与程序设计》第六周学习总结
    作业信息作业所属:https://edu.cnblogs.com/campus/besti/2022-2023-1-CFAP作业要求:https://www.cnblogs.com/rocedu/p/9577842.html#WEEK06作业正文:https://www.cnblogs......