威尼斯娱乐场官网队列对象的等待链表中的线程就有机会被唤醒并继续执行(同样通过KiReadyThread 函数)

当前位置:威尼斯赌场真人网址 > 威尼斯娱乐场官网 > 威尼斯娱乐场官网队列对象的等待链表中的线程就有机会被唤醒并继续执行(同样通过KiReadyThread 函数)
作者: 威尼斯赌场真人网址|来源: http://www.365tester.com|栏目:威尼斯娱乐场官网

文章关键词:威尼斯赌场真人网址,转移函数

  《Windows内核原理与实现》第3章Windows 进程和线程,这一章介绍Windows 操作系统中的两个核心概念:进程和线程,包括它们所涉及的内核数据结构和一些关键算法。本节为大家介绍线程状态转移。

  接下来我们看一下线程等待的情形。一个线程在执行过程中,可能需要依赖某一特定条件,比如等待一个信号量变成有信号状态,或者等待一个系统事件。这些条件都会导致该线程无法继续执行,这时它会进入等待状态,直到所要求的条件满足以后才能继续执行。在WRK 中,等待是通过KeDelayExecutionThread、KeWaitForSingleObject 或KeWaitFor-MultipleObjects 函数来实现的。当一个线程的控制流到达这三个函数之一时,除非等待条件可立即满足,否则,该线程将会进入等待状态,一直到等待的条件满足为止。关于等待的条件如何满足,以及等待机制的内部数据结构等信息,请参考5.4 节。这里,我们只关心线 所示。

  KeDelayExecutionThread 的功能是让当前线程延迟一段时间后再执行, 参见base\ntos\ke\wait.c 文件的233~474 行代码。它利用KTHREAD 结构中的Timer 域来设置一个定时器,并调用KiInsertOrSignalTimer 函数把定时器对象插入到系统的定时器表中。同时把线程的状态设置成等待,然后调用KiSwapThread 交出控制权。在等待期间,也允许有异步过程(APC)被执行,但是,在定时器到期以前,将一直处于等待状态。关于定时器机制,参见本书5.2.5 节。

  . KeWaitForSingleObject 的功能是等待一个对象变成有信号状态, 参见base\ntos\ke\wait.c 文件的999~1 296 行代码。它允许调用者指定超时值,所以,如果在超时以前,对象仍然处于无信号状态,则等待也将结束。它同样利用KTHREAD结构的Timer 域来设置定时器,并把定时器对象加入到自己的等待链表中。除非此等待可以立即满足,否则,将设置线程的状态为等待,然后调用KiSwapThread 交出控制权。在等待期间,允许APC 对象被交付执行。

  一旦线程的状态被置成等待,并且控制权交出去以后,什么时候再次获得控制权呢?当内核在检测到等待的条件已经满足以后,会调用KiReadyThread 函数,让线程进入延迟的就绪状态,从而最终有机会再次获得控制权,从以前停止的地方继续执行。有三个函数可以测试线程的等待条件是否满足:KiWaitTest、KiWaitTestSynchronizationObject 和KiWaitTestWithoutSideEffects。5.4 节将会介绍线程与被等待对象之间的数据结构关系,以及等待条件的测试算法。一旦等待条件已经满足,这些等待测试函数就会调用KiUnwaitThread 函数,而KiUnwaitThread 又会进一步调用KiReadyThread 函数。那么,谁会调用这些等待测试函数呢?当然是那些改变对象信号状态的函数,比如KeSetEvent、KeReleaseSemaphore、KeReleaseMutant 等。

  另外,在KeRemoveQueue 函数中,如果一个队列对象中没有项可用或者队列对象中的线程数量达到了设定的***值,则调用此函数的线程也会阻塞,直至有队列项可用或者有线程让出所占用的计数(调用KiActivateWaiterQueue 函数),或者超时。其行为类似于KeWaitForSingleObject。一旦出现这样的情形,则当前线程加入到队列对象的等待链表中,并进入等待状态,然后调用KiSwapThread 函数交出处理器控制权。以后,当有新的队列项插入进来(通过KiInsertQueue 函数),或者其他线程调用KiActivateWaiterQueue函数的时候,队列对象的等待链表中的线程就有机会被唤醒并继续执行(同样通过KiReadyThread 函数)。队列对象是内核提供的线程池机制,关于它的工作原理,请参考本书5.4.2 节的介绍。

  其中,StackSwappable 是通过调用KiIsKernelStackSwappable 函数得到的,此函数根据线程对象的EnableStackSwap 域(并且此线程当前运行于用户模式下,而且优先级小于25)来确定是否允许将内核栈换出。从这段代码可以看出,每个处理器的控制块KPRCB结构中都维护了一个等待线程链表,此链表中的线程都有机会在内存紧张的时候将其内核栈换出到外存中。待必要的时候再换回来。换出和换入的过程是由内存管理器中一个称为平衡集管理器的线程来完成的, 参见KeSwapProcessOrStack 函数。它调用KiOutSwapKernelStacks 来处理内核栈的换出过程。而KiOutSwapKernelStacks 则调用MmOutPageKernelStack 函数把所有满足条件的线程的内核栈换出内存。注意,此时线程的状态仍然是等待状态,但是线程对象的KernelStackResident 域为FALSE,说明内核栈不在内存中。当此线程的等待条件被满足,即针对该线程调用KiReadyThread 时,它的状态被置成转移(Transition),参见本节开始处列出的KiReadyThread 函数的代码。当内核栈被换入时,线程的状态被置成延迟的就绪(通过调用KiInsertDeferredReadyList 函数),参见KiInSwapKernelStacks 中的代码。

  因此,一个等待的线程,如果满足了内核栈换出条件,则可能会经历“等待-转移-延迟的就绪”的状态变化过程。内核栈和进程的换入/换出是由Windows 内存管理器的平衡集管理器来完成的,参见本书4.5 节、4.6 节中关于物理内存和工作集管理的详细描述。这里我们只需关心,处于等待状态的线程可能会经历这样一个过程。

  在图3.7 中,还有一个分支尚未介绍,即一个正在运行的线程进入到门等待的状态,威尼斯娱乐场官网然后又回到延迟就绪状态。当一个线程调用了KeWaitForGate 函数时,这一状态变化过程就可能会发生。在Windows 中,门对象是一种分发器对象,等待门对象的线程的内核栈不会被换出内存,而且一旦门对象变成有信号状态,等待门对象的线程就能获得优先级提升,所以,它们有更好的机会被立即执行。因此,相比普通的分发器同步对象,门对象是一种优化和简化,在WRK 中,守护互斥体(guarded mutex)和推锁(push lock)使用门对象来实现互斥和共享访问。门对象仅限于在内核层中使用,它没有被暴露到内核以外。

  至此,我们已经全面了解了Windows 中一个线程的状态变化情况,这些状态变化有些是线程本身的逻辑造成的,而有些则是系统出于更有效地管理可用资源的目的而强加的。当线程数量较多时,系统不得不在某些特定的点上让一个正在运行的线程放弃它的处理器执行权,从而允许其他已经就绪的线程有机会获得处理器资源。在现代计算机系统中,处理器资源是按照一定的粒度(也称为时间片)来管理的,下一节我们将讨论处理器资源的时间管理。

  通用技术、应用领域、企业赋能三大章节,13大技术专场,60+国内外一线人工智能精英大咖站台,分享人工智能的平台工具、算法模型、语音视觉等技术主题,助力人工智能落地。

  dubbo+zookeeper综合小练习[Ajax+jQuery+MySQ

  本书是数据库系统方面的经典教材之一。国际上许多著名大学包括斯坦福大学、耶鲁大学、得克萨斯大学、康奈尔大学、伊利诺伊大学、印度理工学...

网友评论

我的2016年度评论盘点
还没有评论,快来抢沙发吧!