第一章 为什么要“千头万绪”
资源网络收集 感谢原创者
转自http://blog.sina.com.cn/s/blog_5678943c0100d4po.html
本章回答了如下几个问题:
◆ 什么是多任务操作系统?多任务操作系统有哪些类型?它们有何区别?
◆ 为什么要使用多线程呢?为什么不使用多进程?线程、进程,它们到底是什么样的东东?
◆ 多线程是如何实现的?线程是如何切换的?效率怎样?
◆ 多线程设计是如此的诱人,难道什么代价也不用付出?怎样才能很好地进行多线程设计呢?
合作型[cooperative]多任务和抢先式[preemptive]多任务有何不同?
两者的最大区别是谁来把握CPU的分享。前者由程序员的“举止良好”才可做到,后者则由操作系统决定,可以强迫应用程序把CPU分享给别人。
Microsoft Windows的前三个版本(1、2、3)属于合作型多任务操作系统,Windows4.0(即Windows)95后均属于强先式多任务操作系统。
记住:一个永远有反映的UI(User Interface)是很重要的。
线程和进程有何不同?
从Win32的角度看,进程拥有内存和资源。资源则包括核心对象(如文件句柄和线程)、用户资源(如对话框和字符串)、GDI资源(如Device Context和brushes)。
进程本身并不能够执行,它只是提供一个安置内存和线程的地方。(进程就是一大堆对象的拥有权的集合。也就是说,进程可以拥有内存上下文、文件句柄、线程及一大串DLL模块(被载入到这一进程地址空间中)。
进程和内存并没有真正“做”什么事情。一旦CPU开始执行代码,你就拥有了一个“线程”。在同一时间同一进程,你可以拥有一大把线程,执行同一段代码。
为什么不使用多个进程?
较之进程,线程轻便、价廉,启动速度快,退出比较快,对系统资源的冲击比较小。
如果使用多进程,最困难的问题是如何把窗口句柄交给另一个进程。在Win32中,句柄只在其诞生地(进程中)才有意义。这是一种安全警戒,避免某个进程有意无意地危及到另一个进程的资源。
为了分享窗口句柄,你必须明明白白地产生该句柄的一个副本,并且可以被其他进程使用。在一个多线程程序中,所有线程都可以使用这个窗口的句柄,因为句柄和线程生活在同一个进程中。
如果两个线程分属不同的进程,那它们通常没有办法共享任何内存。不同进程间如果要通讯,唯有依赖特别的设计,使之拥有共享内存(shared memory)。
如果两线程属于同一进程,它们将共享所有的内存(包括全局变量、静态变量)。
Context Switching及Context Switch效率
要切换不同的线程,操作系统应先切换该线程所隶属之进程的内存,然后恢复该线程存放在CONTEXT结构中的寄存器值。此过程称为context switch。
注:CONTEXT结构中保存了该线程上次被打断时线程当时的状态,也就是CPU内所有寄存器的内容。
当然,天下没有免费的午餐,线程切换时都要缴点效率税金。
对于单CPU而言,抢先式多任务使电脑看起来可以同时处理多个任务。但微观上看,任一时刻,CPU只能做一件事。
多CPU的好处是,CPU越多,就有越多线程可以同时执行,不需要context switch,从而提高了系统效率。
竞争条件(Race Conditions)和原子操作(Atomic Operations)
注意在多任务操作系统中,一条C指令一定可以安全执行完毕,而不在乎context switch是否发生。
好消息与坏消息
使用线程并非没有代价。采用多线程设计往往会加大程序设计的复杂性,必须做到小心精心安排,才能实现预期目标。
成功的秘诀是小心地规划:谁要什么?何时要?怎么要?