对操作系统的理解 操作系统他就是一个系统软件,他上为软件服务,下为硬件服务,就是一个控制大局的指挥者,将资源进行合理的分配。他是为用户(咱们)服务的,设计了很多接口,让我们能对系统内部的资源进行操作,对系统内部资源我们能获取其信息的,比如Linux的一系列命令。对于程序运行来讲,操作系统会在运行程序前,会初始化好环境,操作系统几个功能,进程管理、内存管理、文件管理、设备管理。
讲讲并发带来的丧失原子性的问题
#include<stdio.h>
#include<threads.h>
int sum = 0;
void do_sum(){
for(int i = 0 ; i < 10000000; i++ ){
sum++;
}
}
void printf(){
printf("sum = %ld",sum);
}
int main(){
create(do_sum);
create(do_sum);
join(print);
}
sum++ 其实是 int t = sum; t++; sum =t;
在并发的情况下 就会出现一些难以理解的一些结果,大于10000000小于20000000 当程序以1->2->3->4->5->6这个顺序走的时候 最后的4没给1,最开始1给了2,这么个流程执行下来,导致并发后sum还是1; 进程状态切换 进程三个状态 就绪态 执行态 阻塞态 就绪态->执行态->阻塞态->就绪态 一定是按照这个执行 进程的调度算法 1.先来的先被服务 2.最短时间的被服务 3.进程执行剩余时间少的被服务 4.时间片轮转 假设设定时间片为2秒,进程按照先后顺序在就绪队列排成一列,对首部第一个进程,先分配给他CPU时间2秒,当时间消耗完,回归到这个队列尾部。 这个时间片设计的大小是非常重要的,设计大了,对这个程序执行的实时性造成影响,设计小了,频繁的切换这个进程是非常消耗时间的。5.优先级调度 你给每一个进程配置一个优先级,CPU按照你进程的优先级,优先级高的先被服务,优先分配资源。为防止有些进程饥饿,随着时间推移要可以修改优先级 6.多级反馈队列 他是优先级调度+时间片轮转的结合 假设第一个队列是 时间片为1 第二个队列是2 第三个队列是4 进程按顺序进入第一个个队列,每一个进程执行完队列对应时间片 就向下一级队列的尾部进行插入 这样就可以大大提高程序的合理执行和实时性 fork之后发生了什么 每一个独立的进程都有自己的虚拟内存,子进程会复制父进程的虚拟内存空间,读是共享,写是复制,当对同一块物理内存上的变量进行修改时,父进程改变之后 会重新去物理内存上找一块内存去存放改变后的 子进程也是如此。 孤儿进程 僵尸进程 父进程提前结束,而子进程还在运行,被Init进程所接管(孤儿进程) 子进程退出,但是父进程没有获取他的状态,子进程变为僵尸进程。 1.通过kill父进程 让Init接管子进程。2.使用signal函数让子进程状态被忽略,交给内核处理。3.父进程使用wait函数去获取子进程状态 进程和线程 进程是资源分配的基本单位,线程是程序执行的基本单位。进程之间很难共享,所以要通过进程间通信,进行传递。线程,很容易的共享信息,只需要将数据复制到全局区、堆区,进程占用内存大,创建进程较慢,线程轻量级,速度快,一个进程可以包含多个线程 临界区 临界区就是访问一个共享资源的(代码片段),这段代码片段的执行叫做原子操作,同时访问同一共享资源也就是其他线程不能中断这这块代码执行 读写锁 读时可以并发,可以多个线程进行访问从而提高效率,而写时只能时单线程。 生产者消费者模型 互斥量+条件变量提升效率,可以用生产者消费者模型去解释,用互斥量导致并发带来丧失原子性的问题,当任务链表为空时,消费者不能获取任务,会导致段错误,为防止这样的问题,判断链表中没有结点的时候为空的时候,使用条件变量,将线程进行休眠,当任务链表有数据的时候,在唤醒线程
|