【简译】Windows 线程基础
翻译一篇关于windows线程的文章,原文在此。第一次翻译,如有错误请多指教
=========================================华丽的分割线============================================
介绍:
在现在的编程世界里,无论你使用的是java、.NET或C++,多线程编程已经成为编程语言不可缺少的一部分了。我要利用多线程的能力写出高响应和可扩展的应用程序。在使用.NET框架我遇到了各种像Task Parallel Library (TPL), Parallel LINQ (PLINQ), Task Factories, Thread Pool, Asynchronous programming modal等等为了并行任务处理的 Framework Class Libraries (FCL)。他们幕后使用的是Windows threads的力量达到并行。理解Windows threads的节本结构有助于实现和理解像TPL、PLINQ等的高级功能。本文将帮助你理解操作系统是如何实现线程的。
Windows threads包括什么:
Windows thread包括了三个基本组件:
1)Thread Kernel Object
2) Stack
3) TEB
这三个组合在一起构成了Windows thread。在分别解释这三个之前先做一个关于Windows kernel 和 kernel objects简明的介绍,他俩是Windows操作系统中最重要的一部分。
什么是操作系统内核:
在任何一个操作系统中,内核是最主要的部件。在应用程序与硬件的交互中,内核提供个一个抽象层。
内核是操作系统在加载中先启动的那一部分,并且一直驻留在物理内存中。它主要功能是管理硬件资并允许其他程序使用这些资源。浏览下列网站以了解更多:
http://en.wikipedia.org/wiki/Kernel_(computing)
什么是内核对象
内核需要维护像进程、线程、文件等众多资源的大部分数据,因此内核使用了"内核数据结构"也叫做内核对象。每个内核对象都是由内核分配并且只能由内核访问的一个内存块。这个内存块是一个数据结构,而这个数据结构的成员维护着这个对象的信息。在所有的对象类型中有些成员(安全描述符,使用计数等)是一样,但大多数数据成员是针对内核对象类型的。内核生成和维护几种内核对象类型,例如rocess objects, thread objects, event objects, file objects, file-mapping objects, I/O completion port objects, job objects, mutex objects, pipe objects, semaphore objects等。使用WinObj了解所有的内核对象类型。
http://technet.microsoft.com/en-us/sysinternals/bb896657.aspx
线程内核对象
每个线程生成一个线程内核对象,它是Windows thread最基本的组件。操作系统使用线程内核对象操作和执行线程,同时它保存了关于线程的统计信息。
线程上下文
每个线程内核对象都包括一组称为线程上下文的CPU 寄存器。上下文对应着线程最后一次执行时的线程的CPU寄存器的状态。线程的这组CPU寄存器被保存在一个CONTEXT结构中。在线程上下文中指令指针和栈指针寄存器是两个最重要的寄存器。栈指针存储着线程内部当前正在执行的函数的栈帧的起始地址。指令指针指向的是下一个要CPU执行的指令。操作系统在切换线程上下文时使用内核对象上下文信息。上下文切换是为了保证执行体可以重新在晚些时候同一点开始的一个存储和恢复线程状态的方法。下表显示了一些存储在线程内核对象关于线程的其他重要信息。
Property Name | Description |
CreateTime | This field contains the time when the Thread was created. |
ThreadsProcess | This field contains a pointer to the EPROCESS Structure of the Process that owns this Thread. |
StackBase | This field contains the Base Address of this Thread’s Stack. |
StackLimit | This field contains the end of the Kernel-Mode Stack of the Thread. |
TEB | This field contains a pointer to the Thread’s Environment Block. |
State | This field contains the Thread’s current state. |
Priority | This field contains the Thread’s current priority. |
ContextSwitches | This field counts the number of Context Switches that the Thread has gone through (switching Contexts/Threads). |
WaitTime | This field contains the time until a Wait will expire. |
Queue | This field contains a Queue for this Thread. |
Preempted | This field specifies if the Thread will be preempted or not. |
Affinity | This field contains the Thread’s Kernel Affinity. |
KernelTime | This field contains the time that the Thread has spent in Kernel Mode. |
UserTime | This field contains the time that the Thread has spent in User Mode. |
ImpersonationInfo | This field contains a pointer to a structure used when the Thread is impersonating another one. |
SuspendCount | This field contains a count on how many times the Thread has been suspended. |
栈
一旦线程内核对象被创建,系统会分配内存给他用作线程栈。每个线程有自己的栈,他们用来管理在线程中函数内部变量和传递实参给正在执行的函数。当函数执行时,它会添加一些像实参和局部变量的状态数据到栈顶,而当函数退出时,他负责从栈中删除这些数据。除此之外,线程栈还可以存储函数调用的位置为了允许return语句返回当前位置。
每个线程有两个线程栈:用户模式栈和内核模式栈。
用户模式栈
用户模式栈用来存储局部变量和传递给方法的实参。它也存储表明了当当前方法返回时线程下一个要执行的方法的地址。默认Windows分配1MB给用户模式栈。
内核模式栈
当应用程序代码传递实参给内核函数时使用内核模式栈。为了安全,Windows复制每个从线程的用户模式栈到内核模式栈通过用户模式代码传递给内核的实参。一旦拷贝完成,内核可以验证实参值,同时因为应用程序不可以访问内核模式栈,实参值被验证后应用程序便不能修改,OS内核代码就开始操作他们了。另外,内核调用自身方法和内核模式栈传递自己的实参,存储函数局部变量和返回值。32位系统的内核模式栈是12KB而64位系统是24KB(均为Windows)。
通过以下链接了解更多:
http://www.linfo.org/kernel_space.html
http://en.wikipedia.org/wiki/Stack-based_memory_allocation
http://en.wikipedia.org/wiki/Call_stack
Thread environment block (TEB)
TEB是一块在用户模式下分配和初始化的内存。TEB包括内存的一页(在x86和x64的CPU下是4KB)
TEB包含的一个重要的信息是关于被SEH(Microsoft Structured Exception Handling)使用的异常处理信息。TEB存储着线程的异常处理链的头部。每个线程进入的try块在这个链表头插入一个节点。当线程退出时从链表中删除这个节点。通过下面这个链接了解更多关于SEH的信息:
http://www.microsoft.com/msj/0197/Exception/Exception.aspx
另外,TEB包括thread-local storage data。在多线程应用程序中,常会出现维护一个线程独有的数据的寻求。这个线程指定数据存储的地方叫thread-local storage。通过下面这个链接了解更多关于thread-local storage信息:、
http://msdn.microsoft.com/en-us/library/windows/desktop/ms686749(v=vs.85).aspx
TEB的一些重要属性
Property Name | Description |
ThreadLocalStorage | This field contains the thread specific data. |
ExceptionList | This field contains the Exception Handlers List used by SEH |
ExceptionCode | This field contains the last exception code generated by the Thread. |
LastErrorValue | This field contains the last DLL Error Value for the Thread. |
CountOwnedCriticalSections | This field counts the number of Critical Sections (a Synchronization mechanism) that the Thread owns. |
IsImpersonating | This field is a flag on whether the Thread is doing any impersonation. |
ImpersonationLocale | This field contains the locale ID that the Thread is impersonating. |
OS如何运行threads
OS在线程内核对象中保存所有为了线程调度或执行需要的信息。除了这些OS还在线程内核对象中存储了线程栈和线程TEB的地址。
OS在一个双向链表里维护着所有的内核对象。
OS重复上述行为从系统启动到系统结束。
线程内核对象维护着线程上下文结构,而这个结构对应着线程最后一次执行的CPU寄存器状态。每隔大约20ms,OS线程调度器查询当前在双向链表的线程内核对象。线程调度器选择一个可调度的的线程内核对象并加载存储在它的线程上下文的CPU寄存器的值。这个行为叫做上下文切换。此时,线程执行代码和操作在他自己的地址空间的数据。再过大约20ms后,调度器保存CPU寄存器值到线程上下文。调度器再一次检查剩下的可调度的线程内核对象,并选择一个加载它的上下文到CPU寄存器中继续执行。
OS重复上述行为从系统启动到系统结束。
所有的线程都不是可调度的
系统调度只是可调度的线程,在系统中大多数线程不是可调度的。例如,有些线程对象可能有一个suspend count大于0.这意味着这个线程是暂停的并且不应该被在然和CPU时间内被调度。除了暂停线程,许多其他线程不是可调度的因为它们正在等待一些事情的发生,像有些线程可能在等待一些锁得到释放。系统不会分配CPU时间给那些什么也不做的线程。如果机器有多个CPU,OS的为公平加载线程到CPU的算法更复杂。Windows可以在同步的每个CPU上调度不同的线程使得多线程实现真正的并发。在这种类型的系统上Windows内核操作所有的管理器和线程的调度。在你的代码里你不需要做任何特定的事情去获得多处理器提供的优势,你要做的是在你的代码里更好的利用这些CPU
进程和线程
(主要讲了进程和线程之间的关系,就不翻译了)
引用
- CLR via C#, Third Edition (February 10, 2010) By Jeffrey Richter
- Windows via C/C++ Fifth Edition (December 2007) by Jeffrey Richter and Christophe Nasarre
- Introduction to NT Internals - Alex Ionescu's Blog
- Processes and Threads
【简译】Windows 线程基础的更多相关文章
- 【windows核心编程】 第六章 线程基础
Windows核心编程 第六章 线程基础 欢迎转载 转载请注明出处:http://www.cnblogs.com/cuish/p/3145214.html 1. 线程的组成 ① 一个是线程的内核 ...
- Windows核心编程:第6章 线程基础
Github https://github.com/gongluck/Windows-Core-Program.git //第6章 线程基础.cpp: 定义应用程序的入口点. // #include ...
- 《windows核心编程系列》五谈谈线程基础
线程基础 与前面介绍的进程一样,线程也有两部分组成.一个是线程内核对象.它是一个数据结构,操作系统用它来管理线程以及用它来存储线程的一些统计信息.另一个是线程栈,用于维护线程执行时所需的所有函数参数和 ...
- Windows内核基础知识-8-监听进程、线程和模块
Windows内核基础知识-8-监听进程.线程和模块 Windows内核有一种强大的机制,可以在重大事件发送时得到通知,比如这里的进程.线程和模块加载通知. 本次采用链表+自动快速互斥体来实现内核的主 ...
- CLR via C# 读书笔记-26.线程基础
前言 这俩个月没怎么写文章做记录分享,一直在忙项目上线的事情,但是学习这件事情,停下来就感觉难受,clr线程这章也是反复看了好多遍,书读百遍其义自见,今天我们来聊下线程基础 1.进程是什么,以及线程起 ...
- Clr Via C#读书笔记---线程基础
趣闻:我是一个线程:http://kb.cnblogs.com/page/542462/ 进程与线程 进程:应用程序的一个实例使用的资源的集合.每个进程都被赋予了一个虚拟地址空间. 线程:对CPU进行 ...
- [CLR via C#]25. 线程基础
一.Windows为什么要支持线程 Microsoft设计OS内核时,他们决定在一个进程(process)中运行应用程序的每个实例.进程不过是应用程序的一个实例要使用的资源的一个集合.每个进程都赋予了 ...
- 线程基础(CLR via C#)
1.线程基础 1.1.线程职责 线程的职责是对CPU进行虚拟化.Windows 为每个进程豆提供了该进程专用的线程(功能相当于一个CPU).应用程序的代码进入死循环,于那个代码关联的进程会&quo ...
- 《CLR via C#》读书笔记 之 线程基础
第二十五章 线程基础 2014-06-28 25.1 Windows为什么要支持线程 25.2 线程开销 25.3 停止疯狂 25.6 CLR线程和Windows线程 25.7 使用专用线程执行异步的 ...
随机推荐
- css怎么引用某张图片?链接要怎么写
总结一下 <a href="D:\xxx"> <img src="./xxx.jpg">
- ACM——简单排序
简单选择排序 时间限制(普通/Java):1000MS/3000MS 运行内存限制:65536KByte总提交:836 测试通过:259 描述 给定输入排序元素 ...
- Objective-C 成员变量的访问修饰即成员变量可见性解析
总体来说Objective-C的访问成员变量可见性和C++基本一样,只是多了个@package. 以下是详细说明: 例子: @interface CTPerson : NSObject { @priv ...
- Javascript 数组自定义排序,并获取排序后的保存原索引的同序数组(堆排序实现)
比如数组A: [ 0: 5, 1: 2, 2: 4, 3: 3, 4: 1 ] 排序后的结果为:[1, 2, 3, 4, 5],但是有时候会有需求想要保留排序前的位置到一个同位数组里,如前例则为:[4 ...
- ZOJ 1013 Great Equipment(DP)
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=13 题目大意:说的是有三种不同的装备,分别是头盔,盔甲,战靴需要运输, ...
- 关于C++对汉字拼音的处理——终结篇
以前写过了3个博文,都是关于汉字转拼音的,后来发现都不是很“完美”的解决方案,第一个和第二个利用的unicode编码的范围进行确定汉字的拼音,但是难免有遗漏,这个在后面的实践中发现的,后来第三个方法是 ...
- 查找PHP的配置文件
查找PHP的配置文件 先写了一个 <?php phpinfo();?>然后在浏览器中浏览一下(之前我百度说在Configuration File 这个位置看) 结果竟然显示 Loaded ...
- Linux文件权限学习总结
一.用户对文件或目录都有哪些权限? 四种:读.写.执行.没有权限 二.如何表示这四种权限? 如果用十进制数字表示,分别为:4.2.1.0:如果用字符表示,分别为:r.w.x.-.个人觉得,使用chmo ...
- 如何在WCF中集成unity
第一种是代码方式: 点击打开链接http://blogs.microsoft.co.il/gadib/2010/11/30/wcf-and-unity-20/ 还有一种方式可以扩展成配置文件,有时间再 ...
- 快速理解webStroage
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...