当前位置:C++技术网 > 精选软件 > Windows核心编程入门:6 什么是触发状态

Windows核心编程入门:6 什么是触发状态

更新时间:2016-05-15 16:07:33浏览次数:1+次

    在《Windows核心编程入门4:什么是内核对象,什么是用户对象》中,我们讨论内核对象时,提到了资源。系统用内核对象来管理硬件资源。内核对象里有相关的状态信息可以记录硬件的使用状态,系统根据这些状态信息就可以很好的管理硬件。
    操作系统将硬件视为资源,而且计算机中所有程序的运行,都是操作硬件。比如,播放音乐的软件,要操作声卡。我们用记事本打字,系统要操作显卡,更新屏幕上显示的内容。只不过,对我们我们来说,在系统包装之下,我们似乎淡忘了,我们使用的所有软件,都是在操作硬件。系统为了让我们更好的理解,也就将硬件抽象为各种资源,取了各种名称。这样我们也就不用想着硬件是怎么回事。
    不管怎么样,你都要知道,一台电脑,实际上是一套硬件的组合。一般情况下,每一个部件基本上是唯一的。比如,只有一个CPU硬件,只有一个内存条,只有一个硬盘等等。构成一个电脑,只需要每一个部分的一个就可以了。至于说,多CPU、双内存条、多硬盘的组合,只是提高电脑的性能罢了。
    计算机中的这些硬件,总是有限的。相对于进程线程来说,这些硬件的数量是非常少的。我们可以轻松创建一个线程,多线程操作系统中,我们可以同时运行很多的线程,可能是成千上万个。那么这么多的进程线程都运行起来,你无法做到一个线程给一套计算机硬件的。所以,操作系统就让所有的进程线程来共享使用一套计算机硬件。这是必然的结果。
    在每一个部件都是唯一的情况下,操作系统无法实现同时运行多个线程。因为一个CPU在某一时刻,只可能运行一个线程。CPU物理实体只有一个,这是硬件决定的。而线程很多都是双核甚至是四核的CPU,CPU硬件内有两个或者四个处理器执行单元,这样一来,可以同时运行两个或者四个线程。这样就是真正意义上的同时运行多个程序,这也是我们熟知的多任务系统。然而在一个CPU只有一个处理器执行单元情况下,一次只能执行一个线程。但是我们知道,操作系统运行在这样的硬件上,还是可以叫做多任务操作系统。为什么呢?
    在单CPU执行单元的情况下,虽然在一个时刻只有一个线程执行,但是因为CPU执行速度很快,所以,CPU可以让多个线程轮流的执行一小段时间,比如1毫秒,这样在人类看来,每一个线程执行的任务的进度都在向前推进,而且因为执行速度和切换速度很快,让人类感觉这些线程在同时运行,这也就是多任务的原理。
    就算你有多个CPU,你也无法满足波涛汹涌的线程大军,所以,硬件是永远无法跟上软件的发展的。所以,硬件共享是不可避免的。而且,因为软件的存活周期都很短,你可能在前一秒启动了软件,在后一秒就关闭了软件。软件的运行周期是来无影去无踪的。而硬件则不然,硬件只要没有坏,就可以一直存活着。所以,这也给硬件共享提供了支持。硬件执行速度很快,加上软件不会一直永久存留,所以没有必要给一个软件配一个硬件,这也就是现代通用计算机的做法。这样可以大大提到硬件的使用效率。如果拍照程序不使用CPU了,那么播放器程序可以继续使用CPU,而且两者可以轮流的使用CPU。如果拍照程序关闭了,那么播放器可以独占CPU了。这样硬件一直都在工作,利用率是很高的。计算机技术里,提高硬件的利用率是一个很光荣的事情,也是可以降低使用成本的事情,所以这是计算机技术发展追逐的一个方向。
    这些现象都给资源共享提供了现实基础。所以,我们可以很理所应当的接受资源共享的概念。操作系统也就有这样的一个使命。幸好硬件是没有生命没有意识的,否则人类如此的剥削,硬件绝对不干。如果人工智能发展成熟,或许计算机会评估硬件长期运行带来的损害,会对人类的做法有所反应的。至少,在现在,我们依然是共享硬件,最大化硬件的使用效率。
    那么在操作系统中,多个线程共享使用硬件,则需要一些规则来保证秩序,这样才能很好的满足所有的程序。特别是,多个线程需要合作完成一个任务时,会让情况变得复杂。第一个线程处理的结果,会交给第二个线程处理,第二个线程处理的结果再交个第三个线程处理。三个线程处理时还是使用的同一个内存块。不仅有硬件资源的共享,还有相互的合作。一旦哪里出错,将会导致任务无法完成。
    当然,对于硬件资源的轮流使用,这是操作系统管理的事,对于我们应用程序来说,不用担心。这些管理硬件的事情,正是操作系统内核要做的事情。操作系统将硬件管理的事情屏蔽掉了,然后抽象为资源的状态。而这些状态都是记录在相关的内核对象里的。我们用的最多的就是在同步中。在多个线程或者进程同步执行一个任务时,对于各个步骤的状态的处理尤为重要。如果我们不知道每一个步骤的处理结果,我们无法做后续的工作。如果我们只是一个单一的工作,不与其他的进程线程打交道,其实状态倒是不太重要。比如说,我们一个人吃饭,吃完了就吃完了,自己一个人就离开了饭堂。但是如果是几个人一起吃饭,别人都相互要关注状态,如果大家都吃完了,就可以一起走了。如果你一个人吃完了,那就等等其他人了。
    那么什么是同步呢?同步,同步,不就是一同步行。大意是,一起玩,而且大家要保持一致。你和其他人的动作行为要一致,大家都往前走,你不走或者往后走,这就不是同步了。或者接力赛中,一个个的往下传递,如果你不保持一致,你不接上一个的或者不传给下一个,就让你和其他人不一致了,也就不同步了。本应该同步的事情,你不同步的做,结果事情就做不好了。
    在同步中,我们也就是要观察上一个的状态,处理自己的状态供下一个观察和接受。那么我们最关心的是哪一个状态呢?我们自然总是关心自己应该做什么,什么时候去做。总想着不能让自己掉链子,免得挨揍。所以我们总是会盯着上一个人的状态,一旦他处理完了,也就轮到自己做事了。所以,最重要的状态就是上一个的完成状态。只要上一个人完成了他那一步,我们就可以开始我们这一步了。如果上一步没有完成,我们就只有一个字,等!
    那么到这里,我应该提到了本文要将的概念了,那就是触发状态。其实触发状态也就是一个动作的结束,或者叫做完成态。只有你要等待的事情结束了,完成了,我们才可以开始做我们的事情。这个理解是一个通用的理解。你在这个理解的基础上,再去看Windows操作系统的触发状态,不可能不理解了,而且理解的不是一般的清楚。
    那么相对于触发状态,就是未触发状态。简单来说,未触发也就是未完成状态,未结束状态。这个状态是同步场景中需要的。
    而同步和触发状态,恰恰也是在资源共享的时候表现出的尤为明显。资源的共享表现为多个进程线程的轮流使用,多个线程可以是共同合作完成一个任务,也可以是不相关的,只是都要用到同一个硬件才发生了资源共享。轮流使用资源也是一种同步方式。
    下面是核心编程的触发状态的总结:
进程、线程:
未触发(FALSE):运行的时候
  触发(TRUE ):结束运行的时候

事件触发:操作完成,等待的线程可以继续工作。
可等待的计时器:指定时间或间隔时间触发
信号量:对资源计数(最大资源数和当前可用资源数)
    每种对象的触发规则不同,对象被触发,也就告诉系统等待此对象的线程可以来操作自己了。
    未触发状态实际上属于被占用状态。虽然规则不同,但是基本的道理是一样的,在上面已经描述了。我们在编程中,通常是一些函数来等待我们需要的资源的触发状态,如果资源没有达到触发状态,我们就要等待,或者放弃执行任务。
典型等待函数如下:
WatiForSingleObject 让线程主动进入等待,知道指定的内核对象触发。INFINITE(-1)死等。传入0表示等待的时间为0,也就是立马返回,不进入等待状态。
WaitForMultipleObject 等待多个对象(1-64个之间),返回值减去WAIT_OBJECT_0得到对象的索引
    最后还是那句话,大道至简!触发状态就是完成状态。等待资源的线程发现其他线程操作资源已经完成(处于触发状态)了,自己就可以继续执行了。虽然最后就这么一句话,但是真正要深入理解到位,并非易事,好在本文详细的展开了讲解。说实话,在开始学习的时候,我对触发状态总是模糊不清的。我们调用等待函数等待,等待内部实际上是操作系统内核对资源的管理和协调。我们所说的硬件资源的共享使用,都是内核程序来完成的。我们应用程序就只是调用了一下等待函数,就可以得到共享资源使用。然而内核中,却要记录各个线程的等待状态和等待的资源,只要资源一释放,内核就要将资源分配给等待的线程使用。而这些触发状态,其实也都是在内核中使用的,应用程序只要理解这么一个概念就行了,我们要知道等待函数的含义。至于触发状态如何记录的,如何更改的,这些都是内核的事情了。如果你不是写操作系统,你都不用管内部的事情了。