线程与进程
线程与进程理论
1.进程和线程以及他们的区别
–进程:一个程序在一个数据集上的一次运行过程。系统资源分配的单位。
一个程序在不同数据集合上运行或一个程序在同样数据集上的多次运行都是不同的进程。
进程是独立的,有自己的内存空间和上下文环境,无法获取其他进程的存储空间。同一进程的两段代码不能同时执行,除非引入线程。
–线程:进程的一个实体,是被系统独立调度和执行的基本单位,CPU使用的基本单位。
同一进程的线程可以共享同一内存空间。线程是属于进程的,当进程退出时该进程所产生的线程都会被强制退出并清除。线程占用的资源少于进程占用的资源
–进程和线程都可以有优先级
2.进程在内存中的结构
–代码区:存放CPU执行的机器指令,代码区是可共享,并且是只读的
–数据段:全局变量、静态变量、常量(编译后知道大小)(未初始化的在一个区域(BBS区),初始化的在相邻区域(数据区))
•全局变量:定义在函数外面,其他文件也能使用(external linkage)
•静态变量:static 关键字修饰的变量:
–函数外定义:全局变量,只在当前文件中可见( internal linkage)
–函数内定义:全局变量,只在此函数内可见
–(C++)类中定义:全局变量,只在此类中可见
–栈区:由编译器自动分配释放,存放函数的参数值、返回值和局部变量,在程序运行过程中实时分配和释放,栈区由操作系统自动管理,无须程序员手动管理
–堆区:堆是由malloc()函数分配的内存块,使用free()函数来释放内存,堆的申请释放工作由程序员控制,容易产生内存泄漏
–进程地址空间:内核地址空间+用户地址空间(代码段、数据段、堆、栈、共享库)
3.堆和栈的区别
栈:函数参数、返回地址、局部变量(运行入口知道大小)
1.编译器自动分配释放,存放函数的参数值,局部变量的值等。
2.申请后的响应:若栈的剩余空间大于申请空间,系统将为程序提供内存,否则提示栈溢出
3.大小限制:向低地址扩展,连续的内存区域,栈顶地址和栈最大容量是系统事先规定好的。如果申请的空间超过栈的剩余空间将栈溢出
4.申请效率:系统自动分配,速度快,程序员无法控制
5.存储的内容:函数调用时进栈顺序:主函数下一条指令的地址(函数调用语句的下一条可执行语句)、函数的各个参数(大多数c编译器中参数是从右往左入栈)、函数的局部变量。 调用结束的出栈顺序:局部变量、函数参数(从左到右)、栈顶指针指向最开始存的地址(即主函数的下一条指令)
堆:运行期间动态分配的内存空间(运行的时候才知道大小)
1.程序员自己分配释放,分配方式类似于链表
2.申请后的响应:操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时会遍历该链表,寻找第一个空间大于所申请空间的堆结点,将该结点从空闲结点链表删除,分配该结点的空间给程序。会在这块内存空间中的首地址处记录本次分配的大小。 这样delete语句才能正确释放本内存空间。由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动将多余的那部分重新放入空闲链表中
3.大小限制:向高地址扩展,不连续的内存区域,用链表存储,遍历方向是由低地址向高地址。堆大小受限于计算机系统的有效虚拟内存。获得的空间更大更灵活
4.申请效率:用new分配,速度慢,容易产生内部碎片,使用方便
5.存储的内容:一般在堆的头部用一个字节放堆的大小
4.进程状态
创建(信息设置完但资源有限)
运行(占用cpu)
就绪(等待分配cpu)
等待(等待某个是啊金的发送)
终止(进程完成执行)
5.进程间的通信如何实现
通信的方式有:信号、信号量、消息队列、共享内存、管道、有名管道
–管道(pipe):半双工通信,数据单向流动;只能父子进程通信;速度慢
–有名管道(FIFO):任何进程都能通信;速度慢
–信号量(semophore):计数器,控制多个进程对共享资源的访问(多进程或线程的同步方法);不能传递复杂消息
–信号:用于通知接收进程某个事件已经发送
–消息队列:消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递少、管道只能承载无格式字节流以及缓冲区大小受限的缺点;容量受限,第一次读的时候要考虑上一次没有读完数据的问题 需要消息复制,不需考虑同步问题,不适宜信息量大或操作频繁的场合
–共享内存:映射一段能被其他进程访问的内存,由一个进程创建,可被多个进程访问,要保持同步。与信号量结合使用,用来达到进程间的同步及互斥,最快的IPC方式 不需要消息复制,信息量大,快捷,在任意数量的进程之间进行高效双向通信的机制。
–套接字:可用于不同机器间的进程通信,由ip地址和端口号连接而成
6.进程调度
选择一个可用的进程到cpu上执行 进程进入系统,会被加入到作业队列(包括系统的所有进程)队列通常用链表实现,头结点指向的链表的第一个和最后一个pcb块的指针,每个pcb包括一个指向就绪队列的下一个pcb的指针域
运行—>就绪:IO请求(–>IO队列–>IO结束);时间片结束;创建一个子进程(等待子进程结束);等待中断(中断发生)
PCB:
1.进程标志 进程状态 程序计数器 寄存器
2.cpu调度信息:进程优先级、调度队列指针、其他调度参数
3.内存管理信息:基址寄存器 界限寄存器 页表/段表
4.记账信息:cpu时间、实际使用时间、时间界限、记账数据、作业或进程数量
5.I/O状态信息:分配给进程的IO设备列表、打开文件列表
7.线程状态
创建(new)、就绪(runnable/start)、运行(running)、阻塞(blocked)、等待(waiting)、时间等待(time waiting) 和 消亡(dead/terminated)。在给定的时间点上,一个线程只能处于一种状态
8.线程同步的方式
–互斥量 Synchronized/Lock:采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问
–信号量 Semphare:它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量
–事件(信号),Wait/Notify:通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较操作
9.处理机调度
–先来先服务(FCFS,First-Come-First-Served): 此算法的原则是按照作业到达后备作业队列(或进程进入就绪队列)的先后次序来选择作业(或进程)。
–短作业优先(SJF,Shortest Process Next):这种调度算法主要用于作业调度,它从作业后备队列中挑选所需运行时间(估计值)最短的作业进入主存运行。
–时间片轮转调度算法(RR,Round-Robin):当某个进程执行的时间片用完时,调度程序便停止该进程的执行,并将它送就绪队列的末尾,等待分配下一时间片再执行。然后把处理机分配给就绪队列中新的队首进程,同时也让它执行一个时间片。这样就可以保证就绪队列中的所有进程,在一给定的时间内,均能获得一时间片处理机执行时间。
–高响应比优先(HRRN,Highest Response Ratio Next): 按照高响应比((已等待时间+要求运行时间)/ 要求运行时间)优先的原则,在每次选择作业投入运行时,先计算此时后备作业队列中每个作业的响应比RP然后选择其值最大的作业投入运行。
–优先权(Priority)调度算法: 按照进程的优先权大小来调度,使高优先权进程得到优先处理的调度策略称为优先权调度算法。
–多级队列调度算法:多队列调度是根据作业的性质和类型的不同,将就绪队列再分为若干个子队列,所有的作业(或进程)按其性质排入相应的队列中,而不同的就绪队列采用不同的调度算法。
10.说一说进程同步有哪几种机制
原子操作、信号量机制、自旋锁管程、会合、分布式系统
11.中断和轮询的特点
对I/O设备的程序轮询的方式,是早期的计算机系统对I/O设备的一种管理方式。它定时对各种设备轮流询问一遍有无处理要求。轮流询问之后,有要求的,则加以处理。在处理I/O设备的要求之后,处理机返回继续工作。尽管轮询需要时间,但轮询要比I/O设备的速度要快得多,所以一般不会发生不能及时处理的问题。当然,再快的处理机,能处理的输入输出设备的数量也是有一定限度的。而且,程序轮询毕竟占据了CPU相当一部分处理时间,因此,程序轮询是一种效率较低的方式,在现代计算机系统中已很少应用。
程序中断通常简称中断,是指CPU在正常运行程序的过程中,由于预先安排或发生了各种随机的内部或外部事件,使CPU中断正在运行的程序,而转到为响应的服务程序去处理。
轮询——效率低,等待时间很长,CPU利用率不高。
中断——容易遗漏一些问题,CPU利用率高。
12.同步和互斥
1.同步是进程之间合作完成某功能,是进程之间的直接关系
2.互斥是多个进程公用某临界资源,是进程之间的间接关系
3.(互斥是不允许两个线程同时占有一个资源。同步是在互斥的基础上,再加了访问次序,比如生产消费者模式,需要先生成在消费。比如希尔排序,需要大的间隔度排序完,才能排步数小的)
经典同步问题, 生产消费者模式(Java多线程中也有)
13.
线程&锁
1.什么是死锁? 死锁产生的条件?
1.死锁的概念
在两个或者多个并发进程中,如果每个进程持有某种资源而又等待其它进程释放它或它们现在保持着的资源,在未改变这种状态之前都不能向前推进,称这一组进程产生了死锁。通俗的讲,就是两个或多个进程无限期的阻塞、相互等待的一种状态。
2.死锁产生的四个必要条件
•互斥:至少有一个资源必须属于非共享模式,即一次只能被一个进程使用;若其他申请使用该资源,那么申请进程必须等到该资源被释放为止;
•占有并等待:一个进程必须占有至少一个资源,并等待另一个资源,而该资源为其他进程所占有;
•非抢占:进程不能被抢占,即资源只能被进程在完成任务后自愿释放
•循环等待:若干进程之间形成一种头尾相接的环形等待资源关系
死锁的处理策略;鸵鸟策略、预防策略、避免策略、检测与恢复策略
2.死锁预防
–打破互斥条件。即允许进程同时访问某些资源。但是有的资源是不允许被同时访问的。像打印机等等,这是有资源本身的属性所决定的。所以这种办法并无实用价值
–打破不可抢占条件。即允许进程强行从占有者那里多去某些资源。就是说,当一个进程已占有了某些资源,他又申请新的资源,但不能立即被满足时,它必须释放所有占有的全部资源,然后再重新申请。它所释放的资源可以分配给其他进程。这就相当于该进程占有的资源被隐蔽地强占了,这种预防死锁的方法实现起来困难,会减低系统性能。
–打破占有且申请条件。可以实行资源与预先分配策略。即进程在运行前一次性的向系统申请他所需要的全部资源,如果某个进程所需要的全部资源得不到满足,则不分配资源,此进程暂不运行。只有当系统能够满足当前进程的全部资源需求时,才一次性的将所申请的资源全部分配给该进。由于运行的进程已占有了它所需要的全部资源,所以不会发生占有资源又申请资源的现象,因此不会发生死锁。但是这种策略也有如下缺点
•在许多情况下,一个进程在执行之前不可能知道他所需要的全部资源。这是由于进程在执行时是动态的,不可预测的;
•资源利用率低。无论所分配资源和使用到,一个进程只有在占有所需要的全部资源后才能执行。即使有些资源做后才被该进程用到一次,但该进程在生存期间却一直占有他们,造成长期占着不用的状况。这显然是一种极大的资源浪费
•降低了进程的并发性。因为资源有限,又加上存在浪费,能分配到所需全部资源的进程个数就必然少了
–打破循环等待条件,实行资源有序分配策略。采用这种策略,即把资源实现分类编号,按号分配,使进程在申请,占用资源时不会形成环路。所有进程对资源的请求必须严格按资源序号递增的顺序提出。进程占用了小号资源,才能申请大号资源,就不会产生环路,从而预防了死锁。这种策略与前面的策略相比,资源的利用率额系统吞吐量都有很大提高,但是也存在以下缺点:
•限制了进程对资源的请求,同时给系统中所有资源合理编号也是件困难事,并增加了系统开销
•为了遵循按编号申请的次序,暂不使用的资源也需要提前申请,从而增加了进程对资源的占用时间
3.线程如何避免死锁
1.固定加锁的顺序(针对锁顺序死锁)
2.开放调用(针对对象之间协作造成的死锁) 在一个锁内尽量不要调用其他带锁的方法
3.使用定时锁–>tryLock() 如果等待获取锁时间超时,则抛出异常而不是一直等待!
4.银行家算法
4.如何理解分布式锁
分布式锁,是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调它们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要不出来防止彼此干扰来保证一致性,在这种情况下,便需要使用分布式锁
5.临界区问题
【共享数据的互斥】 临界区:在该区中进程可能改变共同变量、更新一个表、写一个文件;没有两个进程能同时在临界区内执行。
do {
【进入区】 // 请求允许进入其临界区
临界区
【退出区】
剩余区
} while (true);
eg. Peterson算法
int turn; // 表示哪个进程可以进入临界区
boolean flag[2]; // 表示哪个进程想要进入临界区
// Pi进程的结构-------------------------------
do {
// 进入区
flag[i] = true;
turn = j;
while (flag[i] && turn == j);
// 临界区
flag[i] = false; // Pi最多在Pj进入临界区一次后就能进入---有限等待
// 剩余区
} while (true);
满足3个要求: 互斥(进程在临界区内执行,其他进程就不能在其临界区内执行) 前进(如果没有进程在其临界区执行且有进程需进入临界区,那么只有那些不在剩余区内执行的进程可参加选择,以确定谁能下一个进入临界区,且这种不能无线) 有限等待:从一个进程请求允许进入临界区到进入临界区为止,其他进程允许进入其临界区的次数有限
信号量 信号量S是一个整数型变量,信号量分为计数信号量(初始化为可用资源的数量)和二进制信号量(互斥锁)。 除了初始化外,只能通过两个标准【原子】操作:wait()和signal()来访问(这些操作被成为P测试和V增加)
// 进程需要资源的时候
wait(S) {
while (S <= 0); // 被阻塞----忙等待
S–;
}
// 进程释放资源的时候
signal(S) {
S++;
}
这里定义的信号量【自旋锁】的主要缺点: 忙等待:当一个进程位于其临界区内时,其他试图进入临界区的进程需要在进入区连续第循环,浪费了cpu时钟 优点:进程在等待锁时不需要上下文切换,节省时间(如果锁占用时间短)
克服忙等:进程信号量不为正时不忙等二十阻塞自己,放入一个与信号量相关的等待队列中,状态为等待。
6.线程同步与阻塞的关系?同步一定阻塞吗?阻塞一定同步吗?
1.线程同步与阻塞没有一点关系
2.同步和异步关注的是消息通信机制(synchronous communication / asynchronous communication)。所谓同步,就是在发出一个调用时,在没有得到结果之前,这个调用就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由调用者主动等待这个调用的结果。而异步则是相反,调用在发出之后这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立即得到结果。而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。
3.阻塞和非阻塞关注的是程序在等待调用结果(消息、返回值)时的状态。阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。非阻塞调用指在不能立即得到结果之前,该调用不会阻塞当前线程
储存器管理
1.什么是缓冲区溢出?有什么危害?其原因是什么?
缓冲区溢出是指计算机向缓冲区填充数据的时候超过了缓冲区本身的容量,溢出的数据覆盖在了合法数据上;
危害有以下两点:
–程序崩溃,导致拒绝额服务
–跳转并且执行一段恶意代码
造成缓冲区溢出的主要原因就是程序中没有检查用户输入的参数
2.分页和分段有什么区别
段式存储管理是一种符合用户视角的内存分配管理方案。在段式存储管理中,将程序的地址空间划分为若干段(segment),如代码段,数据段,堆栈段;这样每个进程有一个二维地址空间,相互独立,互不干扰。段式管理的优点是:没有内碎片(因为段大小可变,改变段大小来消除内碎片)。但段换入换出时,会产生外碎片(比如4k的段换5k的段,会产生1k的外碎片)
页式存储管理方案是一种用户视角内存与物理内存相分离的内存分配管理方案。在页式存储管理中,将程序的逻辑地址划分为固定大小的页(page),而物理内存划分为同样大小的帧,程序加载时,可以将任意一页放入内存中任意一个帧,这些帧不必连续,从而实现了离散分离。页式存储管理的优点是:没有外碎片(因为页的大小固定),但会产生内碎片(一个页可能填充不满)。
两者的不同点:
•目的不同:分页是由于系统管理的需要而不是用户的需要,它是信息的物理单位;分段的目的是为了能更好地满足用户的需要,它是信息的逻辑单位,它含有一组其意义相对完整的信息;
•大小不同:页的大小固定且由系统决定,而段的长度却不固定,由其所完成的功能决定;
•地址空间不同: 段向用户提供二维地址空间;页向用户提供的是一维地址空间;
•信息共享:段是信息的逻辑单位,便于存储保护和信息的共享,页的保护和共享受到限制;
•内存碎片:页式存储管理的优点是没有外碎片(因为页的大小固定),但会产生内碎片(一个页可能填充不满);而段式管理的优点是没有内碎片(因为段大小可变,改变段大小来消除内碎片)。但段换入换出时,会产生外碎片(比如4k的段换5k的段,会产生1k的外碎片)。
1.什么是虚拟内存
虚拟内存允许执行进程不必完全在内存中。虚拟内存的基本思想是:每个进程拥有独立的地址空间,这个空间被分为大小相等的多个块,称为页(Page),每个页都是一段连续的地址。这些页被映射到物理内存,但并不是所有的页都必须在内存中才能运行程序。当程序引用到一部分在物理内存中的地址空间时,由硬件立刻进行必要的映射;当程序引用到一部分不在物理内存中的地址空间时,由操作系统负责将缺失的部分装入物理内存并重新执行失败的命令。这样,对于进程而言,逻辑上似乎有很大的内存空间,实际上其中一部分对应物理内存上的一块(称为帧,通常页和帧大小相等),还有一些没加载在内存中的对应在硬盘上
注意,请求分页系统、请求分段系统和请求段页式系统都是针对虚拟内存的,通过请求实现内存与外存的信息置换。
2.虚拟内存的应用与优点
虚拟内存很适合在多道程序设计系统中使用,许多程序的片段同时保存在内存中。当一个程序等待它的一部分读入内存时,可以把CPU交给另一个进程使用。虚拟内存的使用可以带来以下好处:
–在内存中可以保留多个进程,系统并发度提高
–解除了用户与内存之间的紧密约束,进程可以比内存的全部空间还大
3.页面置换算法有哪些
1.最佳置换算法(Optimal):即选择那些永不使用的,或者是在最长时间内不再被访问的页面置换出去。(它是一种理想化的算法,性能最好,但在实际上难于实现)。
2.先进先出置换算法FIFO:该算法总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面予以淘汰。
3.最近最久未使用置换算法LRU(Least Recently Used):该算法是选择最近最久未使用的页面予以淘汰,系统在每个页面设置一个访问字段,用以记录这个页面自上次被访问以来所经历的时间T,当要淘汰一个页面时,选择T最大的页面。
4.Clock置换算法:也叫最近未用算法NRU(Not RecentlyUsed)。该算法为每个页面设置一位访问位,将内存中的所有页面都通过链接指针链成一个循环队列。当某页被访问时,其访问位置“1”。在选择一页淘汰时,就检查其访问位,如果是“0”,就选择该页换出;若为“1”,则重新置为“0”,暂不换出该页,在循环队列中检查下一个页面,直到访问位为“0”的页面为止。由于该算法只有一位访问位,只能用它表示该页是否已经使用过,而置换时是将未使用过的页面换出去,所以把该算法称为最近未用算法。
5.最少使用置换算法LFU:该算法选择最近时期使用最少的页面作为淘汰页。
4.颠簸/抖动
颠簸本质上是指频繁的页调度行为,具体来讲,进程发生缺页中断,这时,必须置换某一页。然而,其他所有的页都在使用,它置换一个页,但又立刻再次需要这个页。因此,会不断产生缺页中断,导致整个系统的效率急剧下降,这种现象称为颠簸(抖动)。
内存颠簸的解决策略包括:
–如果是因为页面替换策略失误,可以修改替换算法来解决这个问题;
–如果是因为运行的程序太多,造成程序无法同时将所有频繁访问的页面调入内存,则要降低多道程序的数量;
–否则,还剩下两个办法:终止该进程或增加物理内存容量。
5.局部性原理
1.时间上的局部性:最近被访问的页在不久的将来还会被访问。
2.空间上的局部性:内存中被访问的页周围的页也很可能被访问。
6.CPU中的缓存和操作系统中的缓存分别是什么?
操作系统的缓存是指快表。在操作系统中,为提高系统的存取速度,在地址映射机制中增加一个小容量的联想寄存器,即快表,用来存放当前访问最频繁的少数活动页面的页号。当某用户需要存取数据时,根据数据所在的逻辑页号在快表中找到其对应的内存块号,再联系页内地址,形成物理地址。如果在快表中没有相应的逻辑页号,则地址映射仍可以通过内存中的页表进行,得到空闲块号后必须将该块号填入快表的空闲块中。如果快表中没有空闲块,则根据淘汰算法淘汰某一行,再填入新的页号和块号。快表查找内存块的物理地址消耗的时间大大降低了,使得系统效率得到了极大的提高。
CPU中的缓存是指高速缓存。CPU的执行速度越来越快,系统架构越来越先进,而主存的结构和存取速度改进则较慢,因此,高速缓存技术将越来越重要。 高速缓冲存储器是位于CPU和内存之间的临时存储器,它的容量比内存小但交换速度快。在高速缓冲存储器中的数据是内存中的一小部分,但这一小部分是短时间内CPU即将访问的。当CPU调用大量数据时,就可避开内存直接从高速缓冲存储器中调用,从而加快读取速度。
7.存储器管理
存储器多层结构:寄存器,高速缓存,主存,磁盘 程序装入与链接
分配方式:连续分配和离散分配
–顺序动态分配:
•首次适应
•循环首次适应
•最佳适应(找到刚好合适的)
•最坏适应(每次找到最大的)
–动态重定位分配:
•紧凑法: 将碎片合并成大的空间, 但是影响系统效率
•离散分配:分页,分段
–分页:是物理大小,由系统决定,页面大小是固定的
–分段: 大小是逻辑,用户决定的,段的大小是动态的
–分页:页表存储在内存中,cpu先访问页表,再从页表中得到页号得到的物理地址,其中cpu访问两次内存,速度会明显变慢。通常会用高速缓存(“快表”),缓存当前访问到的页号对应的物理页面,如果没有命中,再去内存中访问页表。
–分段: 方便编程,信息共享,信息保护,动态增长,动态链接
–段页式:段表寄存器记录了段表的大小和起始地址,段表中的每条信息记录了段内页面的页表和起始地址,根据页表可以找到每个页面的位置。 段表=>页表=>最终页面 三次访问内存, 实际会设置高速寄存器,根据段号和页号,查看是否在缓存中命中
I/O管理
一.操作系统与设备之间的IO
简单来说(详细的请看《现代操作系统》),操作系统通过设备驱动程序访问IO设备。方式有:
1.轮询方式:
CPU主动在各种设备中轮询检查状态,有数据就IO。
2.中断方式:
设备有数据的时候,发出中断,由CPU决定要不要响应中断,然后中断,去处理设备的IO。CPU不用经常轮询设备状态。被动接收中断就行。
3.DMA直接存储器访问方式:
如果1个字节的数据中断一次,传1KB的数据得中断1024次,太浪费CPU时间,于是有了DMA方式,CPU只需要把开头和结束的地址告诉DMA,中间由DMA完成数据IO。CPU从字节干预解放到数据块的干预。
4.通道控制方式:
DMA方式只能控制一个设备的一块数据,多块数据还是要CPU干预多次。于是有了通道来控制IO,它比DMA更强大,能控制多块数据,多个设备的IO,更加解放了CPU参与IO过程。
二.操作系统与用户进程间的IO
(进程中的线程才是CPU基本的执行/调度单元,下面用线程举例,用socket举例) 设备来的数据放在内核cache中,需要用户线程去内核cache中取数据,复制到自己进程的cache中。有5中读取数据方式:
1.阻塞:
用户线程调用某些系统函数去内核取数据,直到数据到达内核cache前,该线程处于阻塞状态,等待数据到达。
2.非阻塞
用户线程去取数据,不管内核cache有没有数据,都直接返回,可能拿到数据,也可能拿不到,不会使线程进入阻塞态。
3.IO多路复用
多路就是一个线程管理多路IO,线程还是被阻塞调用,其中一路或几路IO有数据了就返回。需要线程遍历全部IO,判断是哪个IO有数据。 例如 socket 的 select() 函数,线程调用 select() 进入阻塞态,任何一个IO有数据了,线程就退出阻塞态,获得机会继续执行。
4.信号驱动IO
给一个IO注册一个信号和信号触发的回调函数,一旦信号被触发,回调函数里读取数据。 例如给 socket 注册一个“可读”的信号,当数据来了,可读的时候,信号被触发,执行回调函数从内核cache复制数据到用户空间。
5.异步IO
异步IO中,操作系统完成了数据从内核到用户空间的拷贝后,以信号的方式通知用户线程可以下一步操作。省去了用户线程阻塞下来拷贝数据的过程。
IO管理
假设一台服务器需要被1万个客户端连接。方法有:
1.单路:
最简单的一个线程管理一个客户端的socket IO,那么需要1万的线程,假设每个线程占内存3MB,需要300G内存,单台服务器没那么大的内存,并且操作系统最大线程数有限制,unix下一个进程好像是最多只能开 4096 个线程。
2.IO 多路复用:
socket一旦多起来,单路IO 就扛不住了,需要一个线程管理多个 socket IO,下面都是在一个线程内的情况。
3.select
一个线程管理多个socket IO,调用 select() 进入阻塞态,任何一个IO有数据则返回,由于不知道是哪个 socket 有数据,需要遍历所有 socket fd 去判断,当1万个 socket 大部分都是有IO的时候,效率较高,如果只是那么几百个有IO,此方法效率较低。
4.epoll 和 kqueue
epoll 是 linux 下的,kqueue 是 unix 下的。 由于 select 需要遍历全部的 socket fd,效率较低,于是有了 epoll, kqueue 方式,kqueue 管理多个IO,阻塞调用等待函数,当有一个或多个IO事件,kqueue 直接返回多个IO事件的 socket fd,不需要遍历全部 socket fd,效率较高。
假设一个 socket 连接的对象是 3 kb,8G的内存可以管理 280w 个连接。
•select,epoll,kqueue 原理
已知的情况 内核中注册 socket 的 IO 中断处理的回掉函数,有 IO 了会回调该函数。
select: select 管理多个 socket,select 收到一个来自网卡 IO 中断就返回,不知道这个中断对应是哪个 socket fd 的。需要用户线程遍历判断。
epoll: epoll 收到一个 IO 中断,会去查找这个中断对应哪个 socket fd。 epoll 中建立一个红黑树(平衡二叉树的一种),红黑树查找很高效。 用户注册感兴趣的 socket 事件,就是把这个 socket fd 插入到红黑树中,用中断号做key,可以理解为(中断号,socket fd)的二元组。 用户移除事件就是,删除树上的某个节点。
然后收到一个IO中断,epoll 把网卡数据拷贝到内核cache,根据中断号在红黑树中查找对应的 fd,把 fd 加入到就绪链表中,准备返回给用户线程。用户直接得到就绪的 fd。
kqueue: 收到 socket IO 中断去哈希表中查找对应的 socket fd,再把它放到一个链表里,返回。 用户注册一个感兴趣的事件,就是往哈希表中添加一个 fd。
磁盘调度算法
磁盘I/O传输时间
Ta = Ts + 1/2r + b/rN
•Ts 寻道时间(时间最长 最需要优化)
•1/2r 旋转延时的时间为磁盘旋转一周的时间的一半
•b/rN
•b 传输的比特数
•N 磁道上的比特数
•r 磁盘转数
磁盘调度算法
通过优化磁盘访问请求顺序来提高磁盘访问性能
•寻道时间是磁道访问最耗时的部分
•同时会有多个在同一磁盘上的I/O请求
•随机处理磁盘访问请求的性能很差
先进先出算法(FIFO)
•按顺序处理请求
•公平对待所有进程
•在有很多进程的情况下 接近随机调度的性能
磁盘访问序列 = 98,183,37,122,14,124,65,67 初始磁头位置 53
最短服务时间优先(SSTF)
•选择从磁臂当前位置需要移动最少的I/O请求
•总是选择最短寻道时间
磁盘访问序列 = 98,183,37,122,14,124,65,67 初始磁头位置 53
扫描算法(SCAN)
磁臂在一个方向上移动 访问所有未完成的请求 直到磁臂到达该方向上最后的磁道 也称为电梯算法(elevator algorithm)
•中间磁道的访问性能较好 两头的比较差 C-SCAN算法改进了这个缺点
磁盘访问序列 = 98,183,37,122,14,124,65,67 初始磁头位置 53
循环扫描算法(C-SCAN)
限制了仅在一个方向上扫描 当最后一个磁道也被访问过了以后 磁币返回到磁盘的另外一段再次进行
•就算对头没有I/O请求也要走到头 浪费了 C-LOOK算法改进了这个缺点
C-LOOK算法
磁臂先到达该方向上最后一个请求处 然后立即反转 而不是先到最后点路径上的所有请求
N步扫描(N-Step-SCAN)算法
用于解决磁头粘着问题
•磁头粘着(Arm Stickiness)现象
–SSTF SCAN CSCAN等算法中 可能出现磁头停留在某处不动的情况
–进程反复请求对某一磁道的I/O操作
•将磁盘请求队列分成长度为N的子队列
•按FIFO算法依次处理所有子队列
•扫描算法处理每个队列
双队列扫描算法(FSCAN)
FSCAN算法是N步扫描算法的简化 只将磁盘请求队列分成两个子队列 可以减少平均等待时间
•把磁盘I/O请求分成两个队列
•交替使用扫描算法处理一个队列
•新生成的磁盘I/O请求放入另一队列中 所有的新请求都将被推迟到下一次扫描时处理
文件管理
1.文件系统种类
文件系统是操作系统用于明确磁盘或分区上的文件的方法和数据结构;即在磁盘上组织文件的方法。也指用于存储文件的磁盘或分区,或文件系统种类。操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统。文件系统由三部分组成:与文件管理有关软件、被管理文件以及实施文件管理所需数据结构。从系统角度来看,文件系统是对文件存储器空间进行组织和分配,负责文件存储并对存入的文件进行保护和检索的系统。具体地说,它负责为用户建立文件,存入、读出、修改、转储文件,控制文件的存取,当用户不再使用时撤销文件等。
1.FAT
常PC机使用的文件系统是FAT16。像基于MS-DOS,Win 95等系统都采用了FAT16文件系统。在Win 9X下,FAT16支持的分区最大为2GB。我们知道计算机将信息保存在硬盘上称为“簇”的区域内。使用的簇越小,保存信息的效率就越高。在FAT16的情况下,分区越大簇就相应的要大,存储效率就越低,势必造成存储空间的浪费。并且随着计算机硬件和应用的不断提高,FAT16文件系统已不能很好地适应系统的要求。在这种情况下,推出了增强的文件系统FAT32。同FAT16相比,FAT32主要具有以下特点:
1.同FAT16相比FAT32最大的优点是可以支持的磁盘大小达到32G,但是不能支持小于512MB的分区。
基于FAT32的Win 2000可以支持分区最大为32GB;而基于 FAT16的Win 2000支持的分区最大为4GB。
2.由于采用了更小的簇,FAT32文件系统可以更有效率地保存信息。如两个分区大小都为2GB,一个分区采用了FAT16文件系统,另一个分区采用了FAT32文件系统。采用FAT16的分区的簇大小为32KB,而FAT32分区的簇只有4KB的大小。这样FAT32就比FAT16的存储效率要高很多,通常情况下可以提高15%。
3.FAT32文件系统可以重新定位根目录和使用FAT的备份副本。另外FAT32分区的启动记录被包含在一个含有关键数据的结构中,减少了计算机系统崩溃的可能性。
2.NTFS
NTFS文件系统是一个基于安全性的文件系统,是Windows NT所采用的独特的文件系统结构,它是建立在保护文件和目录数据基础上,同时照顾节省存储资源. 减少磁盘占用量的一种先进的文件系统。使用非常广泛的Windows NT 4.0采用的就是NTFS 4.0文件系统,相信它所带来的强大的系统安全性一定给广大用户留下了深刻的印象。Win 2000采用了更新版本的NTFS文件系统??NTFS 5.0,它的推出使得用户不但可以像Win 9X那样方便快捷地操作和管理计算机,同时也可享受到NTFS所带来的系统安全性。
NTFS 5.0的特点主要体现在以下几个方面:
1.NTFS可以支持的分区(如果采用动态磁盘则称为卷)大小可以达到2TB。而Win 2000中的FAT32支持分区的大小最大为32GB。 2. NTFS是一个可恢复的文件系统。在NTFS分区上用户很少需要运行磁盘修复程序。NTFS通过使用标准的事物处理日志和恢复技术来保证分区的一致性。发生系统失败事件时,NTFS使用日志文件和检查点信息自动恢复文件系统的一致性。 3. NTFS支持对分区. 文件夹和文件的压缩。任何基于Windows的应用程序对NTFS分区上的压缩文件进行读写时不需要事先由其他程序进行解压缩,当对文件进行读取时,文件将自动进行解压缩;文件关闭或保存时会自动对文件进行压缩。 4. NTFS采用了更小的簇,可以更有效率地管理磁盘空间。在Win 2000的FAT32文件系统的情况下,分区大小在2GB~8GB时簇的大小为4KB;分区大小在8GB~16GB时簇的大小为8KB;分区大小在16GB~32GB时,簇的大小则达到了16KB。而Win 2000的NTFS文件系统,当分区的大小在2GB以下时,簇的大小都比相应的FAT32簇小;当分区的大小在2GB以上时(2GB~2TB),簇的大小都为4KB。相比之下,NTFS可以比FAT32更有效地管理磁盘空间,最大限度地避免了磁盘空间的浪费。 5. 在NTFS分区上,可以为共享资源. 文件夹以及文件设置访问许可权限。许可的设置包括两方面的内容:一是允许哪些组或用户对文件夹. 文件和共享资源进行访问;二是获得访问许可的组或用户可以进行什么级别的访问。访问许可权限的设置不但适用于本地计算机的用户,同样也应用于通过网络的共享文件夹对文件进行访问的网络用户。与FAT32文件系统下对文件夹或文件进行访问相比,安全性要高得多。另外,在采用NTFS格式的Win 2000中,应用审核策略可以对文件夹. 文件以及活动目录对象进行审核,审核结果记录在安全日志中,通过安全日志就可以查看哪些组或用户对文件夹. 文件或活动目录对象进行了什么级别的操作,从而发现系统可能面临的非法访问,通过采取相应的措施,将这种安全隐患减到最低。这些在FAT32文件系统下,是不能实现的。 6. 在Win 2000的NTFS文件系统下可以进行磁盘配额管理。磁盘配额就是管理员可以为用户所能使用的磁盘空间进行配额限制,每一用户只能使用最大配额范围内的磁盘空间。设置磁盘配额后,可以对每一个用户的磁盘使用情况进行跟踪和控制,通过监测可以标识出超过配额报警阈值和配额限制的用户,从而采取相应的措施。磁盘配额管理功能的提供,使得管理员可以方便合理地为用户分配存储资源,避免由于磁盘空间使用的失控可能造成的系统崩溃,提高了系统的安全性。 7. NTFS使用一个“变更”日志来跟踪记录文件所发生的变更。
2.Ext2
Ext2是 GNU/Linux 系统中标准的文件系统,其特点为存取文件的性能极好,对于中小型的文件更显示出优势,这主要得利于其簇快取层的优良设计。
其单一文件大小与文件系统本身的容量上限与文件系统本身的簇大小有关,在一般常见的 x86 电脑系统中,簇最大为 4KB,则单一文件大小上限为 2048GB,而文件系统的容量上限为 16384GB。
但由于目前核心 2.4 所能使用的单一分割区最大只有 2048GB,实际上能使用的文件系统容量最多也只有 2048GB。
至于Ext3文件系统,它属于一种日志文件系统,是对ext2系统的扩展。它兼容ext2,并且从ext2转换成ext3并不复杂。
1.Ext3
Ext3是一种日志式文件系统,是对ext2系统的扩展,它兼容ext2。日志式文件系统的优越性在于:由于文件系统都有快取层参与运作,如不使用时必须将文件系统卸下,以便将快取层的资料写回磁盘中。因此每当系统要关机时,必须将其所有的文件系统全部shutdown后才能进行关机。
如果在文件系统尚未shutdown前就关机 (如停电) 时,下次重开机后会造成文件系统的资料不一致,故这时必须做文件系统的重整工作,将不一致与错误的地方修复。然而,此一重整的工作是相当耗时的,特别是容量大的文件系统,而且也不能百分之百保证所有的资料都不会流失。
为了克服此问题,使用所谓‘日志式文件系统 (Journal File System) ’。此类文件系统最大的特色是,它会将整个磁盘的写入动作完整记录在磁盘的某个区域上,以便有需要时可以回溯追踪。
由于资料的写入动作包含许多的细节,像是改变文件标头资料. 搜寻磁盘可写入空间. 一个个写入资料区段等等,每一个细节进行到一半若被中断,就会造成文件系统的不一致,因而需要重整。
然而,在日志式文件系统中,由于详细纪录了每个细节,故当在某个过程中被中断时,系统可以根据这些记录直接回溯并重整被中断的部分,而不必花时间去检查其他的部分,故重整的工作速度相当快,几乎不需要花时间。
1.Ext4
Linux kernel 自 2.6.28 开始正式支持新的文件系统 Ext4。Ext4 是 Ext3 的改进版,修改了 Ext3 中部分重要的数据结构,而不仅仅像 Ext3 对 Ext2 那样,只是增加了一个日志功能而已。Ext4 可以提供更佳的性能和可靠性,还有更为丰富的功能: 1. 与 Ext3 兼容。执行若干条命令,就能从 Ext3 在线迁移到 Ext4,而无须重新格式化磁盘或重新安装系统。原有 Ext3 数据结构照样保留,Ext4 作用于新数据,当然,整个文件系统因此也就获得了 Ext4 所支持的更大容量。
1.更大的文件系统和更大的文件。较之 Ext3 目前所支持的最大 16TB 文件系统和最大 2TB 文件,Ext4 分别支持 1EB(1,048,576TB, 1EB=1024PB, 1PB=1024TB)的文件系统,以及 16TB 的文件。
2.无限数量的子目录。Ext3 目前只支持 32,000 个子目录,而 Ext4 支持无限数量的子目录。
3.Extents。Ext3 采用间接块映射,当操作大文件时,效率极其低下。比如一个 100MB 大小的文件,在 Ext3 中要建立 25,600 个数据块(每个数据块大小为 4KB)的映射表。而 Ext4 引入了现代文件系统中流行的 extents 概念,每个 extent 为一组连续的数据块,上述文件则表示为“该文件数据保存在接下来的 25,600 个数据块中”,提高了不少效率。
4.多块分配。当写入数据到 Ext3 文件系统中时,Ext3 的数据块分配器每次只能分配一个 4KB 的块,写一个 100MB 文件就要调用 25,600 次数据块分配器,而 Ext4 的多块分配器“multiblock allocator”(mballoc) 支持一次调用分配多个数据块。
5.延迟分配。Ext3 的数据块分配策略是尽快分配,而 Ext4 和其它现代文件操作系统的策略是尽可能地延迟分配,直到文件在 cache 中写完才开始分配数据块并写入磁盘,这样就能优化整个文件的数据块分配,与前两种特性搭配起来可以显著提升性能。
6.快速 fsck。以前执行 fsck 第一步就会很慢,因为它要检查所有的 inode,现在 Ext4 给每个组的 inode 表中都添加了一份未使用 inode 的列表,今后 fsck Ext4 文件系统就可以跳过它们而只去检查那些在用的 inode 了。
7.日志校验。日志是最常用的部分,也极易导致磁盘硬件故障,而从损坏的日志中恢复数据会导致更多的数据损坏。Ext4 的日志校验功能可以很方便地判断日志数据是否损坏,而且它将 Ext3 的两阶段日志机制合并成一个阶段,在增加安全性的同时提高了性能。
8.“无日志”(No Journaling)模式。日志总归有一些开销,Ext4 允许关闭日志,以便某些有特殊需求的用户可以借此提升性能。
9.在线碎片整理。尽管延迟分配. 多块分配和 extents 能有效减少文件系统碎片,但碎片还是不可避免会产生。Ext4 支持在线碎片整理,并将提供 e4defrag 工具进行个别文件或整个文件系统的碎片整理。
10.inode 相关特性。Ext4 支持更大的 inode,较之 Ext3 默认的 inode 大小 128 字节,Ext4 为了在 inode 中容纳更多的扩展属性(如纳秒时间戳或 inode 版本),默认 inode 大小为 256 字节。Ext4 还支持快速扩展属性(fast extended attributes)和 inode 保留(inodes reservation)。
11.持久预分配(Persistent preallocation)。P2P 软件为了保证下载文件有足够的空间存放,常常会预先创建一个与所下载文件大小相同的空文件,以免未来的数小时或数天之内磁盘空间不足导致下载失败。Ext4 在文件系统层面实现了持久预分配并提供相应的 API(libc 中的 posix_fallocate()),比应用软件自己实现更有效率。
12.默认启用 barrier。磁盘上配有内部缓存,以便重新调整批量数据的写操作顺序,优化写入性能,因此文件系统必须在日志数据写入磁盘之后才能写 commit 记录,若 commit 记录写入在先,而日志有可能损坏,那么就会影响数据完整性。Ext4 默认启用 barrier,只有当 barrier 之前的数据全部写入磁盘,才能写 barrier 之后的数据。(可通过 “mount -o barrier=0” 命令禁用该特性。)
2.ZFS
ZFS源自于Sun Microsystems为Solaris操作系统开发的文件系统。ZFS是一个具有高存储容量. 文件系统与卷管理概念整合. 崭新的磁盘逻辑结构的轻量级文件系统,同时也是一个便捷的存储池管理系统。ZFS是一个使用CDDL协议条款授权的开源项目。
3.HFS
分层文件系统(Hierarchical File System,HFS)是一种由苹果电脑开发,并使用在Mac OS上的文件系统。最初被设计用于软盘和硬盘,同时也可以在在只读媒体如CD-ROM上见到。
HFS文件系统开发过程
HFS首次出现在1985年9月17日,作为Macintosh电脑上新的文件系统。它取代只用于早期Mac型号所使用的平面文件系统Macintosh File System(MFS)。因为Macintosh电脑所产生的数据,比其它通常的文件系统,如DOS使用的FAT或原始Unix文件系统所允许存储的数据更多。苹果电脑开发了一种新式更适用的文件系统,而不是采用现有的规格。例如,HFS允许文件名最多有31个字符的长度,支持metadata和双分支(每个文件的数据和资源支分开存储)文件。
尽管HFS象其它大多数文件系统一样被视为专有的格式,因为只有它为大多数最新的操作系统提供了很好的通用解决方法以存取HFS格式磁盘。
在1998年,苹果电脑发布了HFS Plus,其改善了HFS对磁盘空间的地址定位效率低下,并加入了其它的改进。当前版本的Mac OS仍旧支持HFS,但从Mac OS X开始HFS卷不能作为启动用。
构成方式
分层文件系统把一个卷分为许多512字节的“逻辑块”。这些逻辑块被编组为“分配块”,这些分配块可以根据卷的尺寸包含一个或多个逻辑块。HFS对地址分配块使用16位数值,分配块的最高限制数量是65536。
组成一个HFS卷需要下面的五个结构:
卷的逻辑块0和1是启动块,它包含了系统启动信息。例如,启动时载入的系统名称和壳(通常是Finder)文件。
逻辑块2包含主目录块(Master Directory Block,简称MDB)。
逻辑块3是卷位图(Volume Bitmap)的启动块,它追踪分配块使用状态。
总目录文件(Catalog File)是一个包含所有文件的记录和储存在卷中目录的B*-tree。
扩展溢出文件(Extent Overflow File)是当最初总目录文件中三个扩展占用后,另外一个包含额外扩展记录的分配块对应信息的B*-tree。
Linux
1.Linux常见命令
显示文件目录命令ls 如ls
改变当前目录命令cd 如cd /home
建立子目录mkdir 如mkdir xiong
删除子目录命令rmdir 如rmdir /mnt/cdrom
删除文件命令rm 如rm /ucdos.bat
文件复制命令cp 如cp /ucdos /fox
获取帮助信息命令man 如man ls
显示文件的内容less 如less mwm.lx
重定向与管道type 如type readme>>direct,将文件readme的内容追加到文direct中
2.Linux中显示一个文件最后几行的命令是什么? tail -n 20 filename
tail命令语法 tail -f [ File ] 参数解释: -f 该参数用于监视File文件增长。 -c Number 从 Number 字节位置读取指定文件 -n Number 从 Number 行位置读取指定文件。 -m Number 从 Number 多字节字符位置读取指定文件,比方你的文件假设包括中文字,假设指定-c参数,可能导致截断,但使用-m则会避免该问题。 -b Number 从 Number 表示的512字节块位置读取指定文件。 -k Number 从 Number 表示的1KB块位置读取指定文件。