🎵一、冯诺依曼体系和操作系统
🎈1.1冯诺依曼体系结构
我们常见的台式计算机、笔记本以及不常见的公司使用的服务器,大部分都遵从冯诺依曼体系。
冯诺依曼体系结构主要讲述的是什么呢?它主要向我们介绍了计算机的基本架构:
输入设备:包括键盘、鼠标、扫描仪、写板等。
中央处理器(CPU):含有运算器、控制器等
输出设备:显示器、打印机、网卡等。
我们输入设备输入的数据必须先加载到内存(存储器),才能被CPU处理,CPU能且只能对内存进行读写,不能访问外设(输入设备)。输出设备从内存读取信息。
🎈1.2操作系统
Ⅰ概念
任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。简单来说,操作系统是一款软硬件资源管理的软件,包括:
🖊内核(进程管理,内存管理,文件管理,驱动管理)
🖊其他程序(例如函数库,shell程序等)
Ⅱ目的
设计操作系统的目的是为了与硬件交互,通过合理的管理软硬件资源,为用户提供良好的执行环境。
Linux操作系统内核是用C语言写的,所以它是如何管理硬件呢?操作系统本身并不管理硬件,驱动管理硬件,从硬件获取数据,对数据做管理,用struct结构体描述,把数据做分类描述,对应设备做特定的结构管理起来,比如队列,链表等数据结构。最后交付给操作系统,而我们用户通过操作系统提供的接口查看这些数据信息。
🎵二、进程
🎈2.1基本概念
进程:一个运行起来(加载到内存)的程序。也就是在内存中的程序,进程与程序相比,具有动态属性。
比如Windows下我们打开任务管理器就可以查看当前正在运行的程序,这些都是一个个独立的进程:
🎈2.2描述进程-PCB
进程信息被放在一个叫做进程控制块的数据结构中,也就是PCB。Linux操作系统下的PCB是:task_struct。进程被转化为内核数据结构(task_struct)和进程对应的磁盘代码。
PCB概念的提出,使得对进程管理,变成了对进程对应的PCB相关管理。
task_struct 内容分类:
🖊标示符:描述本进程的唯一标示符,用来区分其他进程。
🖊状态:任务状态,退出代码,退出信号等。
🖊优先级:相对于其他进程的优先级。
🖊程序计数器:程序中即将被执行的下一条指令的地址。
🖊内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。
🖊上下文数据:进程执行时处理器的寄存器中的数据。
🖊I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
🖊记账信息:可能包括处理器时间总和,使用的时间钟总和,时间限制,记账号等。
🖊其他信息。
🎈2.3进程基本指令
👓Ⅰps ajx
ps ajx :显示当前目录下所有进程
我们也可以通过管道检索指定正在运行的进程。比如:
当然,我们看向这些内容并不知道是什么数据,我们可以把它的标头打印出来方便我们查看。
👓Ⅱkill 指令
kill -l 我们查看一下这个指令。
kill指令集下有很多指令,我们这里需要着重关注的有三条指令 :
🖊kill -9 终止进程
🖊kill -19 停止/暂停进程
🖊kill -18 继续进程
我们先来看如何终止一个进程。
这里的PID是进程的编号,Linux下的大多数对进程的操作都是对进程的PID,也可称之为它的ID进行操作。
执行过后,进程就被终止了。还有两个重要的kill指令,后续会提及。
👓Ⅲ getpid && getppid
getpid和getppid是Linux下获取当前进程和父进程id的函数。
//头文件 #include<unisted.h> #include<sys/types.h> //sunopsis pid_t getpid(void); pid_t getppid(void); //返回值 getpid() 返回当前进程ID getppid() 返回当前进程父进程ID
①getpid
我们写一个程序来查看一下它的ID:
#include<stdio.h> #include<unistd.h> #include<stdlib.h> int main() { while(1) { printf("我是一个进程,我的ID是%d\n",getpid()); sleep(1); } return 0; }
那么这个ID它真的可以代表这个进程吗?我们来验证一下:
通过验证,我们发现,确实如此,pid确实可以代表各个进程,就如同我们的学号对应一位同学。
②getppid
在了解pid之后,ppid又是何方神圣呢?ppid是当前进程的父进程的id。按照关系,当前进程是其父进程的子进程。
我们编写一个程序来查看一下父进程的id。
/*myprocess.c*/ #include<stdio.h> #include<unistd.h> #include<stdlib.h> int main() { while(1) { printf("我是一个进程,我的ID是%d,父进程的ID是%d\n",getpid(),getppid()); sleep(1); } return 0; }
我们发现子进程的id每次运行程序都会变化,而父进程的id是不会变化的。也就是说,父进程相对于子进程来说只有一个,而子进程可以经父进程创建生成很多个,执行程序时由子进程来执行,就算挂了也不会影响父进程。而shell执行命令就是以子进程来执行的。
那么这里子进程的父进程到底是什么呢?其实就是当前的命令行解释器:
👓 Ⅳ fork
fork用于创建子进程。
/*fork*/ //头文件 #include<unisted.h> pid_t fork(void); //返回值 //如果创建成功,子进程的ID被返回给父进程,0返回给子进程。如果失败,-1返回给父进程,没有子进程创建并报错。
我们研究一下返回值就会发现一个惊奇的现象:如果创建成功,子进程的PID被返回给父进程,0返回给子进程。失败-1返回给父进程,没有子进程创建。我们发现fork的返回值有两个!!而这个会对我们的程序有什么影响呢?
我们看到,同一段代码执行了两次,这两次一次是父进程执行的,一次是子进程执行的。而在这里我们也可以看出系统和语言的不同,语言是不可能出现有两个返回值这样的情况的。
所以根据这种特性,我们在使用fork的时候,需要使用if条件判断执行。
如果我现在把正在执行的进程的可执行程序给删除,那么进程还会继续执行吗?
我们发现进程还在执行,但是我们查看exe文件会发现闪红并告诉我们deleted。