概念:
进程:进程不过是一个应用程序的一个实例要使用的资源的一个即可。可以认为进程是对OS的资源的虚拟化。
线程:线程是对CPU进行虚拟化。
如果没有线程,那么假如一个进程进入了无限循环,CPU会被占用,而导致系统无法响应。
反之,如果那个进程的代码进入无限循环,与那个进程关联的代码会“冻结”,其他进程(有自己的线程)不会冻结,他们会继续执行!
线程开销
和一切虚拟化机制一样,线程回家产生空间(内存耗用)和时间(运行时的执行性能)上的开销。具体包括:
线程内核对象 OS为每个线程都分配和初始化的数据结构之一。包含了一组对线程进行描述的属性,还包括所谓的线程上下文。上下文是一个内存块,包含了CPU的寄存器集合,对于x64,上下文约使用1240字节的内存。
线程环境块(TEB )TEB是用户模式分配和初始化的一个内存块。TEB耗用一个内存页(x64约4KB)。TEB包含线程的异常处理链首(head)。线程进入每一个try块,都会在链首插入一个节点。线程退出try块时,会删除该节点。另外TEB还包含线程的“线程的本地存储”数据,以及有GDI和Open GL使用的 一些接口。
用户模式栈 用户模式栈用于存储传递给方法的局部变量和实参。它还包含一个地址;指出当前方法返回时,线程接着应该从什么地方开始执行。默认分配约1MB内存。
内核模式栈 应用程序代码向OS中的一个内核模式的函数传递实参时,还会使用内核模式栈。处于安全方面的考虑,针对从用户模式的代码传给内核的任何实参,Windows都会把他们从线程的用户模式栈复制到内核模式栈。应用程序无法修改验证之后的实参值。除此之外,内核会调用它自己内部的方法,并利用内核模式栈传递它自己的实参、存储函数的局部变量以及存储返回地址。64位约24KB
DLL线程链接和线程分离通知 Windows的一个策略是,任何时候在进程中创建一个线程,都会调用那个进程中加载的所有DLL的DLLMain方法,并向该方法传递一个DLL—THREAD—ATTACH标志,类似地,任何时候一个线程终止,都会调用进程中的所有DLL的DLLMain方法,并向该方法传递一个DLL—THREAD—DETACH标志。所有的DLL利用这些通知为进程中创建/销毁的每个线程执行一些特殊的初始化或(资源)清理操作。例如OutLook中加载了大约250个DLL,创建一个新线程都必须先调用250个DLL函数,然后终止时,这250个函数还要再调用一遍。这严重影响了在进程中创建和销毁线程时的性能。
每次上下文切换都要求Windows执行以下操作
1 将CPU寄存器的值保存到当前正在运行的线程的内核对象内部的一个上下文结构中。
2从现有线程集合中选出一个线程来切换,如果该线程由另一个进程拥有,那么开始执行之前,还必须切换CPU“看见”的虚拟地址空间。
3将所选的上下文结构中的值加载到CPU的寄存器中
上下文切换后,CPU执行所选的线程,直到它的时间片到期。Windows大约30毫秒执行一次切换。应该尽可能的避免上下文切换。