当前位置: 首页 > news >正文

初识Linux · 进程(2)

目录

前言:

有关进程的相关理解


前言:

本文会开始慢慢切入进程了,当然,切入进程之前,我们需要再次复习一下操作系统,后面接着是介绍什么是进程,如何查看进程,在Linux中对应的文件是哪个等相关的问题,进程大概会持续更新多节,所以说进程的知识点还是相当杂乱的,就更需要同学们予以注意了。


有关进程的相关理解

首先,我们需要知道,为什么需要操作系统?

操作系统的工作是执行软硬件资源的管理,如何管理硬件上文提及的是通过驱动程序,使得硬件的相关数据组织成为一个链表,操作系统可以直接对链表的信息进行修改,驱动程序再对硬件实施管理,这是先描述再组织,从而实现了管理硬件,那么这是操作系统的一个手段,也就是管理硬件的一个手段而已,它本质上还是要为用户提供良好的,稳定的,高效的,安全的服务,所以需要对相关的资源使用相应的手段进行管理。这是操作系统的目的和手段。

由上文的操作系统的结构图我们可以知道,操作系统里面有进程管理以及各种管理,那么操作系统管理进程的时候,肯定是允许多进程存在的,比如:

这些,都是进程,想看你的电脑里面存在哪些进程,你只需要esc + shift + ctrl打开任务管理器即可,所以现在可以证明,进程是可以存在多个的

那么,什么是进程呢?

这里提问,如果将某个工程的数据和代码加载到内存里面,代码是否会跑起来呢?当然是不会的,因为cpu并没有从里面读取数据,当代码跑起来的时候,就存在了一个进程,难道进程是对应的,已经跑起来的程序吗?当然不是,这是不废话,进程 = PCB + 自己的代码和数据

那么什么是PCB呢?这就有意思了,类比硬件,操作系统管理硬件的时候,需要硬件的信息,从而构建一个链表,再对链表的相关信息增删查改,从而实现管理硬件,那么必然存在一个结构体吧?因为只有结构体可以用来存储多个不同的数据类型。

从而,推理出PCB是对应数据集合的结构体,那么PCB的全称是:process control block 。也就是进程控制块,这就有意思了,进程控制块?不就是结构体吗,那为什么取个进程控制块呢?就是因为操作系统可以直接对PCB进行修改删除等操作,达到对进程控制的效果。

得出结论:进程 = PCB + 自己的代码和数据

那么为什么要有PCB的概念呢?

因为:先描述再组织

所以可以在内存块里面,多个进程之间以链表的形式进行连接,每个PCB里面都有下一个PCB的指针,那么操作系统可就轻松了,原本那么多不着头脑的进程,这下可以直接通过管理链表来实现管理进程了。

那么具体的PCB的名字是什么呢?是task_struct

叫做task是因为外国人认为这是个任务嘛,所以就取名为task了。

进程都是动态运行的,我们如何理解动态运行这个概念呢?

是这样的,在内存块里面,OS占有一席之地,在里面实现对各种软硬件的管理,现在不同的进程进来了,总得有个先后队列吧?

所以存在task_queue的东西,也就是进程队列,不同的进程需要排队的,动态实际上就是多个PCB排队的过程

具体的会放在后面介绍。

现在再来谈谈task_struct的内部属性

首先认识一个点,我们不管是运行指令也好,运行自己编写的代码也好,本质上都是直接创建一个进程,不过指令是一瞬间就运行完成的,我们看不到相关的东西而已,那么什么进程那么多,我们如何区分不同的进程呢?像学校那样,我们每个人都有自己独一无二的学号,进程是同理的,存在一个东西叫做pid,即process id,进程的id,类比学生的学号即可。

说了那么多,我们应该如何看到pid呢?

在此之前,我们应该回想上篇文章介绍的系统调用接口:

我们知道系统调用是操作系统给我们的函数,我们目前从未调用过它,现在,就是调用我们人生中第一个系统调用接口的时候了,我们使用man手册查询可知:

从手册的说明书我们就知道2号接口是系统库函数调用,也就是我们即将学习的getpid:

  1 #include <stdio.h>2 #include <sys/types.h>3 #include <unistd.h>4 5 int main()6 {7   printf("I am a process\nMy pid is %d\n",getpid());                                                                                                                                                          8   return 0;9 }

有意思的还有getpid()函数居然需要两个头文件一起才能使用。

欸,打印结果也是正常,打印的进程id每次都是不一样的,我们的初步目的已经达成了,但是进程肯定是不止就这么点东西的,所以我们应该输入ps -xaj 来看,这里先记着,xaj的顺序无所谓:

  1 #include <stdio.h>2 #include <sys/types.h>3 #include <unistd.h>4 5 int main()6 {7   while(1)8   {9   printf("I am a process\nMy pid is %d\n",getpid());10   sleep(1);11   }                                                                                                12   return 0;13 }

首先改一下代码,死循环方便我们观察:

我们使用管道来筛选出包含test的进程,前两个我们是可以理解的,但是为什么grep也有呢?因为ps -xaj打开了进程,通过管道筛选,筛选也是一个进程,那么我们想要不看它,就可以:

grep -v grep反向筛选出不含grep的即可:

当然了,直接ps -xaj就相当于windows里面的任务管理器,查看所有进程。

我们可以看到,打印出来的pid是14191,在打印出来的head -1中也有pid,也是14191,所以pid打印出来是没问题的。

现在我们再来查看,ppid是个什么东西?ppid全程就是parent process id,也就是父进程的id,有人就有问题了,父进程?这个东西还带有继承的?我们是可以在一个进程中创建多个进程的,用到的函数是fork():

这里有个很有意思很有意思的点,会颠覆你的编程三观的,即这个返回值pid_t,类型本质上是unsigned int,这里就先留个伏笔。

我们先来看一段有意思的代码:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{ printf("I am a father process!\n");fork();printf("I am a child process\n");return 0;
}

试问这段代码的运行结果是什么?

直接看结果:

可以发现打印了两遍第二次的printf,我们可以这样理解,我是一个公司老板,我在没有招员工之前一直再做相同的事,找了员工之后,员工和我做相同的事,但是我之前做的所以工作员工还需要做吗?不需要,所以第一行的printf是不会执行的,父进程原本的代码就是要执行printf的,所以会打印两次child process。

  7   while(1)8   {9     printf("This is parent process:%d\nThis is child process:%d\n",getppid(),getpid());10     sleep(1);                                                                                      11   }

打印出来,对应的父进程的id是22252,子进程id是22239,在ppid 和 pid 下面也得到了验证。

更多的请看后面!!!


感谢阅读!

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 《HTML 与 CSS—— 响应式设计》
  • 机器学习:opencv--图像金字塔
  • 《Nginx核心技术》第16章:实现Nginx的高可用负载均衡
  • HDMI彩条显示——FPGA学习笔记12
  • 从基础到进阶:利用EasyCVR安防视频汇聚平台实现高效视频监控系统的五步走
  • 物业小程序|提升管理效率,打造智慧物业社区
  • mysql学习教程,从入门到精通,MySQL 子查询 子句(11)
  • 恐怖类游戏智能体————恐怖探险家
  • 使用PHP和MQTT构建高效的物联网数据转发服务器流程
  • 基于SpringBoot+Vue的美妆购物系统
  • LAMP环境下项目部署
  • 前端Excel热成像数据展示及插值算法
  • ARM32开发——DMA
  • 011. Oracle-约束
  • 【设计模式】UML类图和六大设计原则
  • [译]如何构建服务器端web组件,为何要构建?
  • 【mysql】环境安装、服务启动、密码设置
  • Android系统模拟器绘制实现概述
  • Angularjs之国际化
  • Debian下无root权限使用Python访问Oracle
  • JavaScript函数式编程(一)
  • Nacos系列:Nacos的Java SDK使用
  • react-native 安卓真机环境搭建
  • React系列之 Redux 架构模式
  • XForms - 更强大的Form
  • 二维平面内的碰撞检测【一】
  • 分享一个自己写的基于canvas的原生js图片爆炸插件
  • 买一台 iPhone X,还是创建一家未来的独角兽?
  • 判断客户端类型,Android,iOS,PC
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 前端相关框架总和
  • 前端之React实战:创建跨平台的项目架构
  • 让你的分享飞起来——极光推出社会化分享组件
  • 如何用vue打造一个移动端音乐播放器
  • Spring第一个helloWorld
  • 好程序员大数据教程Hadoop全分布安装(非HA)
  • ​ 无限可能性的探索:Amazon Lightsail轻量应用服务器引领数字化时代创新发展
  • ​Linux Ubuntu环境下使用docker构建spark运行环境(超级详细)
  • ​卜东波研究员:高观点下的少儿计算思维
  • # Redis 入门到精通(七)-- redis 删除策略
  • (06)Hive——正则表达式
  • (PWM呼吸灯)合泰开发板HT66F2390-----点灯大师
  • (八)c52学习之旅-中断实验
  • (二)Eureka服务搭建,服务注册,服务发现
  • (黑马点评)二、短信登录功能实现
  • (七)glDrawArry绘制
  • ... fatal error LINK1120:1个无法解析的外部命令 的解决办法
  • .NET Micro Framework初体验
  • .net 打包工具_pyinstaller打包的exe太大?你需要站在巨人的肩膀上-VC++才是王道
  • .NET 指南:抽象化实现的基类
  • .Net 中Partitioner static与dynamic的性能对比
  • .NET/C# 使用 ConditionalWeakTable 附加字段(CLR 版本的附加属性,也可用用来当作弱引用字典 WeakDictionary)
  • .NET中的Exception处理(C#)
  • .NET周刊【7月第4期 2024-07-28】
  • /etc/skel 目录作用