本文主要记录我学习《Windows核心编程》第16章——“线程栈”的心得。该章篇幅较小,但较深奥,需要细细体会各个概念,在此特记录我细思后对各知识点的领悟。
一、进程与线程
进程与线程(Process and Thread),是操作系统课程中的一对“纠缠不清”的冤家。通俗来讲,进程是系统进行资源分配和调度的一个独立单元,线程是CPU调度和分派的基本单元,线程是进程内的一个执行单元,是一个可调度实体。(关于他俩的关系,可以参考点击打开链接 )。
进程由两个部分组成:进程内核对象和进程地址空间。其中,进程内核对象是由操作系统维护的一个与特定进程实体相关的结构体,记录进程相关的信息;进程地址空间是进程所拥有的虚拟内存空间,它是一种内存资源,但请注意,它是虚拟内存。
同样的,线程也由两部分组成:线程内核对象和线程栈。线程本身几乎不拥有系统资源,但它能与同属一个进程的线程共享进程的全部资源。但请注意这个“几乎”,事实上,线程也拥有一点系统资源,它就是“线程栈”(除线程内核对象外)。
无论是进程内核对象,还是线程内核对象,都是操作系统用来管理它的一个结构体,其中存放了相关的统计信息。
二、线程栈
线程栈(Thread Stack)是用来存放线程执行时所需要的所有函数参数和局部变量的栈空间。当系统创建线程时,会为线程栈预订(reserve)一块地址空间区域(region),并给区域调拨(commit)一些物理存储器。需要注意的是,这个地址空间区域(线程栈)是在进程地址空间的用户分区中,而不是内核分区中。默认情况下,系统会预订“1MB”的地址空间并调拨两个页面的存储器。当然,这个默认大小是可以通过修改编译器(/F选项)和链接器(/STACK选项)的编译选项来修改的。
在构建应用程序的时候,链接器会把想要的栈的大小写入到.exe或.dll的PE文件头中。当系统创建线程栈的时候,会根据PE文件头中的大小来预订地址空间区域。
如下图,它是在x86机器上的一个线程栈内存模拟图。它的页面大小(Page size)是4KB,分配粒度(Allocation Granularity)是64KB。