hi,我是云边有个稻草人 偶尔中二的博主^(* ̄(oo) ̄)^,与你分享专业知识,祝博主们端午节快乐!
Linux---本节博客所属专栏---持续更新中---欢迎订阅!

目录
[二、操作系统(Operator System)](#二、操作系统(Operator System))
[2.1 概念](#2.1 概念)
[2.2 设计OS的⽬的](#2.2 设计OS的⽬的)
[2.3 核心功能](#2.3 核心功能)
[2.4 如何理解 "管理"](#2.4 如何理解 "管理")
[2.5 系统调用和库函数概念](#2.5 系统调用和库函数概念)
[3.1 基本概念与基本操作](#3.1 基本概念与基本操作)
[(2)task_ struct](#(2)task_ struct)
[3.2 进程状态](#3.2 进程状态)
[耶嘿!---Oops_Little Mix、Charlie Puth(我猜你一定听过)](#耶嘿!—Oops_Little Mix、Charlie Puth(我猜你一定听过))
正文开始------
【Linux系统】第八节---进程概念(上)---冯诺依曼体系结构+操作系统+进程及进程状态+僵尸进程(结合画板一起看,理解效果更好)
一、冯诺依曼体系结构

我们常⻅的计算机,如笔记本。我们不常⻅的计算机,如服务器,⼤部分都遵守冯诺依曼体系。
截⾄⽬前,我们所认识的计算机,都是由⼀个个的硬件组件组成。
- 输⼊单元:包括键盘, ⿏标,扫描仪, 写板等
- 中央处理器(CPU):含有运算器和控制器等
- 输出单元:显⽰器,打印机等
关于冯诺依曼,必须强调⼏点:
- 这⾥的存储器指的是内存
- 不考虑缓存情况,这⾥的CPU能且只能对内存进⾏读写,不能访问外设(输⼊或输出设备)
- 外设(输⼊或输出设备)要输⼊或者输出数据,也只能写⼊内存或者从内存中读取。
- ⼀句话,所有设备都只能直接和内存打交道。
注意------对冯诺依曼的理解,不能停留在概念上,要深⼊到对软件数据流理解上,请解释:(可以看画图板上面的解释)
- 从你登录上qq开始和某位朋友聊天开始,数据的流动过程。
- 从你打开窗⼝,开始给他发消息,到他的到消息之后的数据流动过程。
- 如果是在qq上发送⽂件呢?
二、操作系统(Operator System)
2.1 概念
任何计算机系统都包含⼀个基本的程序集合,称为操作系统(OS)。
笼统的理解,操作系统包括:
- 内核(进程管理,内存管理,⽂件管理,驱动管理)
- 其他程序(例如函数库,shell程序等等)

2.2 设计OS的⽬的
- 对下,与硬件交互,管理所有的软硬件资源
- 对上,为⽤⼾程序(应⽤程序)提供⼀个良好的执⾏环境

2.3 核心功能
在整个计算机软硬件架构中,操作系统的定位是:⼀款纯正的"搞管理"的软件。
2.4 如何理解 "管理"
- 管理的例⼦ - 学⽣,辅导员,校⻓
- 描述被管理对象
- 组织被管理对象
总结 计算机管理硬件
- 描述起来,⽤ struct 结构体
- 组织起来,⽤链表或其他高效的数据结构
2.5 系统调用和库函数概念
- 在开发⻆度,操作系统对外会表现为⼀个整体,但是会暴露⾃⼰的部分接⼝,供上层开发使⽤, 这部分由操作系统提供的接⼝,叫做系统调⽤。
- 系统调⽤在使⽤上,功能⽐较基础,对⽤⼾的要求相对也⽐较⾼,所以,有心的开发者可以对部分系统调⽤进⾏适度封装,从⽽形成库,有了库,就很有利于更上层⽤⼾或者开发者进⾏⼆次开 发。
承上启下
那在还没有学习进程之前,就问⼤家,操作系统是怎么管理进⾏进程管理的呢?很简单,先把进程描述起来,再把进程组织起来!
三、进程
3.1 基本概念与基本操作
- 课本概念:程序的⼀个执⾏实例,正在执⾏的程序等
- 内核观点:担当分配系统资源(CPU时间,内存)的实体。
(1)描述进程-PCB
基本概念
进程信息被放在⼀个叫做进程控制块的数据结构中,可以理解为进程属性的集合。 • 课本上称之为PCB(process control block),Linux操作系统下的PCB是: task_struct。
task_struct---PCB的⼀种
- 在Linux中描述进程的结构体叫做task_struct。
- task_struct是Linux内核的⼀种数据结构类型,它会被装载到RAM(内存)⾥并且包含着进程的信息。
(2)task_ struct
内容分类
- 标⽰符: 描述本进程的唯⼀标⽰符,⽤来区别其他进程。
- 状态: 任务状态,退出代码,退出信号等。
- 优先级: 相对于其他进程的优先级。
- 程序计数器: 程序中即将被执⾏的下⼀条指令的地址。
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
- 上下⽂数据: 进程执⾏时处理器的寄存器中的数据[休学例⼦,要加图CPU,寄存器]。
- I/O状态信息: 包括显⽰的I/O请求,分配给进程的I/O设备和被进程使⽤的⽂件列表。
- 记账信息: 可能包括处理器时间总和,使⽤的时钟数总和,时间限制,记账号等。
- 其他信息 • 具体详细信息后续会介绍
组织进程
可以在内核源代码⾥找到它。所有运⾏在系统⾥的进程都以task_struct链表的形式存在内核⾥。

(3)查看进程
- 进程的信息可以通过 /proc 系统⽂件夹查看 如:要获取PID为1的进程信息,你需要查看 /proc/1 这个⽂件夹。
- ⼤多数进程信息同样可以使⽤top和ps这些⽤⼾级⼯具来获取
(4)通过系统调⽤获取进程标⽰符
- 进程id(PID)
- ⽗进程id(PPID)
cpp
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
printf("pid: %d\n", getpid());
printf("ppid: %d\n", getppid());
return 0;
}
(5)通过系统调⽤创建进程---fork初识
- 运⾏ man fork 认识fork
- fork有两个返回值
- ⽗⼦进程代码共享,数据各⾃开辟空间,私有⼀份(采⽤写时拷⻉)
cpp
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int ret = fork();
printf("hello proc : %d!, ret: %d\n", getpid(), ret);
sleep(1);
return 0;
}
- fork 之后通常要⽤ if 进⾏分流
cpp
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int ret = fork();
if(ret < 0){
perror("fork");
return 1;
}
else if(ret == 0)
{
//child
printf("I am child : %d!, ret: %d\n", getpid(), ret);
}else{
//father
printf("I am father : %d!, ret: %d\n", getpid(), ret);
}
sleep(1);
return 0;
}
注意
- fork为什么会有两个返回值?
- 两个返回值各种给⽗⼦如何返回?
- ⾄于:⼀个变量怎么能让 if 和 else if 同时成⽴这个问题,需要在后⾯才能解释清楚。
3.2 进程状态
(1)Linux内核源代码怎么说
为了弄明⽩正在运⾏的进程是什么意思,我们需要知道进程的不同状态。⼀个进程可以有⼏个状态(在Linux内核⾥,进程有时候也叫做任务)。
进程状态其实就是task_struct结构体内的一个整型变量,在操作系统里面#define宏定义R,S等定义为不同的整型值0,1等, 根据进程的不同状态将task_struct里面的整型变量的值改为对应的状态,这就是状态,未来操作系统根据task_struct里面的整型值来选择如何控制进程(调度,挂起。。。)
下⾯的状态在kernel源代码⾥定义:
bash
/*
*The task state array is a strange "bitmap" of
*reasons to sleep. Thus "running" is zero, and
*you can test for combinations of others with
*simple bit tests.
*/
static const char *const task_state_array[] = {
"R (running)", /*0 */
"S (sleeping)", /*1 */
"D (disk sleep)", /*2 */
"T (stopped)", /*4 */
"t (tracing stop)", /*8 */
"X (dead)", /*16 */
"Z (zombie)", /*32 */
};
- R运⾏状态(running): 并不意味着进程⼀定在运⾏中,它表明进程要么是在运⾏中要么在运⾏队列⾥。
- S睡眠状态(sleeping): 意味着进程在等待事件完成(这⾥的睡眠有时候也叫做可中断睡眠 (interruptible sleep))。
- D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个 状态的进程通常会等待IO的结束。
- T停⽌状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停⽌(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运⾏。
- X死亡状态(dead):这个状态只是⼀个返回状态,你不会在任务列表⾥看到这个状态。
(2)进程状态查看
bash
ps aux / ps axj 命令
- a:显⽰⼀个终端所有的进程,包括其他⽤⼾的进程。
- x:显⽰没有控制终端的进程,例如后台运⾏的守护进程。
- j:显⽰进程归属的进程组ID、会话ID、⽗进程ID,以及与作业控制相关的信息
- u:以⽤⼾为中⼼的格式显示进程信息,提供进程的详细信息,如⽤⼾、CPU和内存使⽤情况等
(3)Z(zombie)-僵⼫进程
- 僵死状态(Zombies)是⼀个⽐较特殊的状态。当进程退出并且⽗进程(使⽤wait()系统调⽤,后⾯讲)没有读取到⼦进程退出的返回代码时就会产⽣僵死(⼫)进程
- 僵死进程会以终⽌状态保持在进程表中,并且会⼀直在等待⽗进程读取退出状态代码。
- 所以,只要⼦进程退出,⽗进程还在运⾏,但⽗进程没有读取⼦进程状态,⼦进程进⼊Z状态
来⼀个创建维持30秒的僵死进程例⼦:
cpp
#include <stdio.h>
#include <stdlib.h>
int main()
{
pid_t id = fork();
if(id < 0){
perror("fork");
return 1;
}
else if(id > 0){ //parent
printf("parent[%d] is sleeping...\n", getpid());
sleep(30);
}else{
printf("child[%d] is begin Z...\n", getpid());
sleep(5);
exit(EXIT_SUCCESS);
}
return 0;
}

(4)僵尸进程的危害
- 进程的退出状态必须被维持下去,因为他要告诉关⼼它的进程(⽗进程),你交给我的任务,我 办的怎么样了。可⽗进程如果⼀直不读取,那⼦进程就⼀直处于Z状态?是的!
- 维护退出状态本⾝就是要⽤数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中, 换句话说,Z状态⼀直不退出,PCB⼀直都要维护?是的!
- 那⼀个⽗进程创建了很多⼦进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数 据结构对象本⾝就要占⽤内存,想想C中定义⼀个结构体变量(对象),是要在内存的某个位置 进⾏开辟空间!
- 内存泄漏?是的!
- 如何避免?后⾯讲。
⾄此,值得关注的进程状态全部讲解完成,下一节来认识另⼀种进程。
完------
耶嘿!---Oops_Little Mix、Charlie Puth(我猜你一定听过)

至此结束------
我是云边有个稻草人
期待与你的下一次相遇!