计算机的硬件体系结构
五大硬件单元:输入设备(如:键盘),输出设备(如:显示器),运算器,控制器
所有的设备都是围绕内存工作的。CPU不能直接从输入设备取数据,而是要去存储器取数据(存储器最主要的工作就是数据缓冲)
键盘输入信息(电信号转换为数字信号)键盘捕捉到我们的输入信息——>放内存缓冲起来——>交给CPU对信息进行处理(翻译输入了哪些字符)——>处理好了再次发给存储器——>通过输出设备网卡(通过网络进行发送信息,将我们的数字信号再次转换为电信号)——>到达对方电脑,对方的网卡接受我们的信号——交给CPU (处理信息)——>放入内存进行输出——>输出设备显示器
任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。
笼统的理解,操作系统包括:
内核(进程管理,内存管理,文件管理,驱动管理)
其他程序(例如函数库,shell程序等等)
与硬件交互,管理所有的软硬件资源为用户程序(应用程序)提供一个良好的执行环境
在整个计算机软硬件架构中,操作系统的定位是:一款纯正的“搞管理”的软件
进程基本概念
用户的角度:是运行中的程序。
操作系统的角度:是程序运行的动态描-PCB,其中包含程序运行的各项信息,实现操作系统对于运行中程序管理。(pcb描述信息:标识符-PID,内存指针,程序计数器,上下文数据进程状态,进程优先级,IO信息,记账信息)
linux下:进程就是task_struct结构体。是操作系统对程序运行的描述,通过这些描述完成对进程的管理。
课本概念:程序的一个执行实例,正在执行的程序等(程序:软件——就是程序员所写的代码,程序本质上都存储在硬盘,因为程序都存储在文件中,文件存储在硬盘里)。
内核观点:担当分配系统资源(CPU时间,内存)的实体。
描述进程-PCB
进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。
课本上称之为PCB(process control block),Linux操作系统下的PCB是: task_struct
描述当前进程处于什么状态应该如何被操作系统调度管理。
进程状态种类:就绪、运行、阻塞。
通过复制调用进程(谁调用他就复制谁)来创建一个子进程。子进程从fork之后进行运行。(这个复制是复制了大部分信息,不是复制全部信息比如进程ID就不会复制的。)
返回值:如果成功复制子进程则返回子进程PID,在父进程中返回子进程PID ;在子进程中返回0;失败返回-1。
#include
2 #include <stdlib.h>
3 #include <unistd.h>
4
5 int main()
6 {
7 printf("leihoua~~\n");
8 return 0;
9 }
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4
5 int main()
6 {
7 fork();
8 printf("leihoua~~\n");
9 return 0;
10 }
~
编译运行一下(步骤如一种)
父进程和子进程都打印了信息。fork()之后他们俩同时从fork之后运行程序。
3. 再次修改main.c:把print函数放到fork函数之前
#include
2 #include <stdlib.h>
3 #include <unistd.h>
4
5 int main()
6 {
7
8 printf("leihoua~~\n");
9 fork();
10 return 0;
11 }
编译运行:
我们发现只输出一次打印信息。因为子进程是fork之后才创建的,fork之后父进程和子进程都运行了return 0.
4. 为什么要创建子进程?
(1)分摊任务处理压力。(2)可以让子进程做另一件事情。这种最常用。
继续修改main.c 根据fork函数的返回值来区分父子进程
vi main.c
#include
2 #include <stdlib.h>
3 #include <unistd.h>
4
5 int main()
6 {
7
8 pid_t pid = fork();
9 if(pid >0)
10 {
11 printf("i m parent\n");
12
13 }else if(pid == 0)
14 {
15 printf("i m child~\n");
16
17 }
20 printf("hello !\n");
23 return 0;
24 }
产生原因:子进程先于父进程退出,为了保存退出原因,因此等待父进程获取状态释放资源。
危害:资源泄露(内存资源的泄露,进程数量的占有)
处理:退出父进程。
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<stdlib.h>
4
5 int main()
6 {
7
8
9 pid_t pid = fork();
10 if(pid > 0)
11 {
12
13 printf("i m parents~\n");
14
15 }else if(pid == 0)
16 {
17 printf("i m a child\n");
18 sleep(6);
19 exit(0); //退出进程;
20 }
21 while(1){
22
23 printf(" i m a zoomProcess");
24 sleep(1);
25 }
26 return 0;
27 }
3 main:main.c
4 gcc $^ -o $@
从上图可以看出我们无法进行任何其他操作,必须中断这个僵尸进程,才能继续输入命令。所以我们必须结束这个僵尸进程。
产生原因:父进程先于子进程退出,子进程就会成为孤儿进程。
特性:运行在后台,父进程变为1号进程(孤儿进程退出后不会成为僵尸进程)。
守护进程:特殊的孤儿进程,在孤儿进程的基础上脱离与终端之间的关系(比如新建回话)。
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<stdlib.h>
4
5 int main()
6 {
7
8
9 pid_t pid = fork();
10 if(pid > 0)
11 {
12
13 printf("i m parents~\n");
14
15 sleep(6);
16 exit(0); //退出进程;
17 }else if(pid == 0)
18 {
19 printf("i m a child\n");
20 }
21 while(1){
22
23 printf(" i m a orphonProcess");
24 sleep(1);
25 }
26 return 0;
27 }
保存程序运行环境的变量,特性:具有进程之间的传递性。
env: 显示所有环境变量
1 #include<stdio.h>
2 #include <unistd.h>
3 #include<stdlib.h>
4
5
6 int main()
7 {
8 char *ptr = getenv("PATH");
9 if(ptr == NULL)
10 {
11 printf("there is no PATH\n");
12 }else {
13 printf("%s\n",ptr);
14 }
15
16 return 0;
17 }
2 env:env.c
3 gcc $^ -o $@
1 #include<stdio.h>
2 #include <unistd.h>
3 #include<stdlib.h>
4
5
6 int main()
7 {
8 char *ptr = getenv("MYVAL");
9 if(ptr == NULL)
10 {
11 printf("there is no MYVAL\n");
12 }else {
13 printf("%s\n",ptr);
14 }
15
16 return 0;
17 }
本质上就是操作系统为进程通过mm_struct描述的虚拟的地址空间,让每个进程都能访问一个完整独立的连续的虚拟地址,经过映射之后,实现物理内存上的离散存储,提高内存利用率。提高内存访问控制。