一、计算机硬件知识
(1)冯·诺依曼体系
a:运算器+控制器=cpu
b:输入设备和输出设备属于外设(除cpu和内存外的都是外设)
c:存储器=内存(不包括硬盘等)
d:对于数据信号,外设只能直接和存储器打交道,
cpu也只能直接和存储器打交道(cpu不能直接与外设联系)
e:以在扣扣上发送消息为例,步骤为:
发送方键盘(发送方输入设备)->发送方内存->qq封装处理消息(cpu)->返回到发送方内存->由发送方网卡(发送方输出设备)进行网络发送->接 收方网卡(接收方输入设备)接收消息->接收方内存->解包(cpu)->返回到接收方内存->接收方显示屏(输出设备)显示
二、操作系统
(1)OS:管理计算机软硬件资源的软件。
OS是一个基本的程序集合,笼统来说包括内核(进程管理、内存管理、文件管理、驱动管理)与其他程序(库函数、shell程序等)。
(2)
管理者:校长
中间人(执行者):辅导员(不做管理决策)
被管理者:学生
【要管理好,管理者和被管理者可以不直接打交道】
【管理者通过数据做数据决策】
管理者:操作系统
中间人(执行者):驱动程序
被管理者:硬盘
【不直接交流,通过OS采集到的硬件数据,而OS采集的硬盘数据由驱动程序提供】
(3)管理层次图如下:
(4)OS的定位
对下进行软硬件资源的管理 + 对上提供良好的执行环境
(5)OS对上只提供各种接口,这些接口称为系统调用。
不同于库函数调用,系统调用要求对系统理解较深,库是基于此又开发的一层,便于降低调用要求。
所以系统接口和库函数接口是上下层关系。
三、进程概念
先把每个学生
描述(用结构体存其数据)起来,再把学生的描述信息传给管理系统(即把学生的描述信息
组织起来)。
(1)基本概念
进程是程序的一个执行实例、正在执行的程序等。对于内核来说,进程是担当分配系统资源(CPU时间、内存)的实体。
(2)进程描述——PCB
PCB:进程被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。
linux系统下的PCB是:task_struct。
【每个进程都有一个结构体,再在每一个结构体内添加一个结构体指针,由此形成一个链表,OS通过该链表管理进程】
【描述进程的结构体称为PCB】
【管理进程其实就是管理进程的PCB】
(3)所以内存中有:OS、一堆进程、与进程对应的一堆PCB
(4)进程与程序的区别:
在硬盘上放着的程序,一旦进入内存就是进程。
程序一进入内存,OS就会给其建立PCB维护起来。
(5)task_struct 的内容分类
-
标识符: 描述本进程的唯一标识符,用来区别其他进程。 PID
-
状态: 任务状态,退出代码,退出信号等。
-
优先级: 相对于其他进程的优先级。
-
程序计数器: 程序中即将被执行的下一条指令的地址。
-
内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。
-
上下文数据: 进程执行时处理器的寄存器中的数据(休学例子、要加图CPU、寄存器)。
-
I/O状态信息: 包括显示的I/O请求,分配给进程是I/O设备和被进程使用的文件列表。
-
记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
-
其他信息。
(6)进程的切换
被中断进程的信息保存在内存中,保存在内存中该进程的PCB中。
(7)
进程的id:
PID 唯一标识符
(8)查询进程:
proc 【进程的信息可以通过 /proc 系统⽂文件夹查看 如:要获取PID为1的进程信息,你需要查看 /proc/1 这个⽂文件夹】
ps 【加参数aux将所有进程的信息展示出来】
ps aux | grep ‘5962’ ->查询PID为5962的进程,grep为管道
系统调用 【通过系统调用同样可以获取进程的PID】getpid()获取当前进程的pid getppid()获得父进程的pid
(9)
所有进程都是bash。
(10)终止进程
ctrl+c
kill [kill -9 6233] 6233为要杀掉进程的PID
(11)创建进程
让程序跑起来
fork()
(12)关于fork()
fork()可创建子进程
fork()有两个返回值
,分别为:给父进程返回子进程的PID、给子进程返回0。 因为孩子的父亲只有一个,而父亲的孩子不一定只有一个,所以子进程给父进程返回自己的PID、给自己返回0。
【关于为什么会有两个返回值:因为当一个程序要返回时说明已经运行完成,子进程已经存在,此时运行返回语句,会因为子进程和父进程的代码共用性而运行两次。返回值的接收会触发写时拷贝(见(13))】
fork()之后,子进程和父进程共享代码 (一个执行另一个也执行),效果见下图;但两者的数据私有,即数据各自保存
eg:
对于下面的程序,
#include
#include
#include
int main()
{
fork();
printf("hello world!,pid:%d,ppid:%d\n",getpid(),getppid());
sleep(1);
return 0;
}
运行结果为:
[root@localhost 1_class]# ./test_static
hello world!,pid:6367,ppid:5962
hello world!,pid:6368,ppid:6367
【显然,下面的显示结果为子进程的显示结果,fork()得到的子进程的PID为:6368。其创建步骤为:bash创建PID为6367的父进程,父进程创建PID为6368的子进程。】
(13)写时拷贝
父子有任何一个进程尝试写入某程序时,OS会为其重新开辟一个空间让其写入。 只有写入时才会单独拷贝,平时共用,可节约空间。
(14)虽然父进程与子进程共享代码,但通常会为父进程和子进程分配不同的代码块。即将程序分流后让父进程和子进程各执行不同的代码块。
如:
#include
#include
#include
int main()
{
pid_t id=fork();
if(id==0) //子进程
{
while(1)
{
printf("child do thing 1……,pid:%d,ppid:%d\n",getpid(),getppid());
sleep(1);
}
}
else if(id>0) //父进程
{
while(1)
{
printf("father do thing 2……,pid:%d,ppid:%d\n",getpid(),getppid());
sleep(3);
}
}
else
{
perror("fork");
}
return 0;
}
//将子进程与父进程的任务利用if语句分割开来
(15)fork()之后子进程和父进程谁先运行并不确定,完全由调度器决定。
四、进程状态
1、状态有哪些?
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):这个状态只是⼀一个返回状态,你不会在任务列表⾥里看到这个状态。
【暂停和睡眠的区别:sleep做事情了,stop没有做事情,什么都没做。】
【sleep为浅度睡眠,可唤醒;D状态为深度睡眠状态,不可强制唤醒。S状态的进程可以被杀死,D状态不能被杀死】
【进程状态信息后面的+号表示是前台运行,没有+说明是后台运行】
【R状态不一定占CPU,但占CPU的一定是R状态】
2、进程状态切换图:
3、僵尸进程
-
僵死状态(Zombies)是⼀一个⽐比较特殊的状态。当进程退出并且⽗父进程(使⽤用wait()系统调⽤)没有读取到⼦子进程退出的返回代码时就会产⽣生僵死(⼫尸)进程
-
僵死进程会以终⽌止状态保持在进程表中,并且会⼀一直在等待⽗父进程读取退出状态代码。
-
所以,只要⼦子进程退出,⽗父进程还在运⾏行,但⽗父进程没有读取⼦子进程状态,⼦子进程进⼊入Z状态
僵⼫尸进程危害:
-
进程的退出状态必须被维持下去,因为他要告诉关⼼心它的进程(⽗父进程),你交给我的任务,我办的怎么样了。可⽗父进程如果⼀直不读取,那⼦子进程就⼀直处于Z状态?是的!
-
维护退出状态本⾝身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说,Z状态⼀直不退出,PCB⼀直都要维护?是的!
-
那⼀个⽗父进程创建了很多⼦子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构对象本⾝身就要占⽤用内存,想想C中定义⼀个结构体变量(对象),是要在内存的某个位置进⾏行开辟空间!
-
内存泄漏?是的!
4、孤儿进程
父进程如果提前退出,那么子进程就称之为“孤儿进程”
孤儿进程会被1号init进程领养,也就是说会由1号进程进行回收。
父进程退出后为什么没有成为僵尸进程?因为父进程的父进程bash会立刻对死掉的父进程进行回收。
五、进程的优先级
1、重要的身份
2、关于进程优先级PRI
cpu资源分配的先后顺序,就是指进程的优先权(priority)。
优先权高的进程有优先执行权利。
配置进程优先权对多任务环境的linux很有用,可以改善系统性能。还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。
3、
NI代表nice值,表示进程可被执行的优先级的修正数值。
默认优先级的值为80,默认nice值为0
优先级越低越晚执行
修改进程优先级的命令:
nice
renice
【开始执⾏行程序就指定nice值:
nice -n -5 ./test】
【
renice -5 -p 5200 //PID为5200的进程nice设为-5】
用top命令更改已存在进程的nice:进入top后按“r”–>输入进程PID–>输入nice值
4、其他概念
-
竞争性: 系统进程数⺫⽬目众多,⽽而CPU资源只有少量,甚⾄至1个,所以进程之间是具有竞争属性的。为了⾼高效完成任务,更合理竞争相关资源,便具有了优先级
-
独⽴立性: 多进程运⾏行,需要独享各种资源,多进程运⾏行期间互不干扰
-
并⾏行: 多个进程在多个CPU下分别,同时进⾏行运⾏行,这称之为并⾏行
-
并发: 多个进程在⼀一个CPU下采⽤用进程切换的⽅方式,在⼀一段时间之内,让多个进程都得以推进,称之为并发