管理内部执行线程的系统的制作方法

文档序号:6409766阅读:1902来源:国知局
专利名称:管理内部执行线程的系统的制作方法
技术领域
本发明一般说来涉及的是在一个远程通信数据系统中的执行机构。更为具体地说本发明涉及的是对在一个进程中内部执行线程的管理。
在实现面向对象的远程通信应用时,将其分成一个表示系统资源(像信道、音调发送器等)和执行该应用控制功能的控制逻辑的对象模型是合适的。控制逻辑进一步又被分成单个活动,像呼叫控制、载体连接控制等等,因而具有不少优点。
应用的执行环境是进程。这里进程一词指的是打算用于一定活动例如一个电话呼叫的运行期环境。进程环境完全位于一个确定的处理器内并包括存储器(堆、堆栈)和执行能力。在进程中伪同时执行线程。进程也包含对象模型。
线程是用于控制逻辑的执行资源。线程的执行是由对象模型产生的事件驱动的。同一事件可能激发几个线程,然后它们以线程优先级次序分发。事件通常作为对外部事件例如对一个由进程接收到的信令消息的响应而产生。
线程可以监视从某个特定的对象来的个别事件,监视从某个对象来的任何事件,监视从一类对象来的个别事件,或者监视从一类对象来的任何事件。一个线程维护它自己的上下文,亦即堆栈和处理器寄存器,但与其它线程共享堆。
线程对于把复杂的活动分成相对独立的子活动提供强有力的支持。线程中逻辑的执行,要么直到它进入需要一个事件继续的状态,要么直到它完成它的执行。当一个线程进入等待状态或者完成了它的执行时,则给其它线程执行的可能性。这意味着所有非同步事件在控制逻辑准备好处理它们时被交付给控制逻辑。
对象模型用作对应用必需的实际对象例如一个ISDN用户的终端、一个连接、一个用户等的抽象。对象通过方法调用--例如通过一个连接对象提供的方法“连接”,为控制逻辑提供服务。对象封装有数据,由此维护它自己的状态。对象也可以通过发送消息给其它进程和从其它进程接收消息而与进程之外的世界通信。
相关技术在US5421013中,一个应用是中介类(agent class)的实例的一个集合,每一中介类具有它自己的消息发送功能。一个应用编程接口提供多线程,该接口包括一个以非抢占方式分配时间给单个中介的主调度进程。
在US5355488中叙述了一种方法,使用该种方法把一个由应用程序接口建立起来的任务在该任务完成后一直保持在一个空闲状态。建立起来的任务保存在一个库中。任务管理器响应一个应用的工作请求,启动在库中对相应于该任务请求的空闲任务的检索。如果在库中存在有相应的空闲任务,则控制交给应用编码执行。
US5345588公开了一种为多线程数字数据处理环境中的每一执行的线程提供每组初始数据的私有备份的方法,该初始数据是在多个线程的上下文中执行的过程所需要的。
US5319782公开了将从第一多任务操作系统调度任务与从第二多任务操作系统寻机调度的函数调用线程同步的方法。第二操作系统包括一组可调用资源。一个任务在一个线程拥有来自第二操作系统的可调用资源期间接合在该线程上。
在US5305455中,一个数据处理系统可运行在多任务方式下,以便包括至少一个具有若干线程的进程。异常管理基于每个线程进行,它与在每个进程基础上进行的相反。
在US5247675中,多任务操作系统允许应用程序影响程序线程的执行安排表,通过为程序线程指定参数,它们构成应用程序。参数指示线程的优先级以及该线程所在的调度类。
发明总结在设计大的实时软件系统例如控制电话交换的软件时,由于电话交换必须实时处理事件而产生的应用的内在复杂性常常使程序难于编写、理解和维护。
本发明的一个目的是为构造这样的软件提供一个框架和一个机构,它的做法是使应用的实时行为容易处理,从而减小软件的复杂性,使其易于编写、理解和维护。
在一个根据本发明管理一个进程中的内部执行线程的系统中,执行线程是由进程内部事件消息驱动的,这些消息是由事件产生函数响应内部或者外部来的事件产生的。内部事件消息分发到具有优先级的事件接收线程。由一个事件管理函数根据事件产生函数的分发类别控制这一分发,并且只对对这些内部消息感兴趣并引起对其出现进行监视的事件接收线程执行。对于每一分发类别存在有若干角色(actor),其中有若干事件接收线程;若干第一实体,它们代表为事件产生函数对于某些事件接收线程进行的一个或者多个监视;若干第二实体,它们代表为事件产生函数对分发类别的监视,每一第二实体有一个已经监视了一个事件接收线程的所有第一实体的表;一个第三实体,它跟踪所有借助于一个第二实体表已经监视了分发类别的事件接收线程;若干事件产生函数,每一个保持一个第一实体表。
在权利要求2到5中有若干上述结构的重要的实施例。
每一第一实体保持一个指向事件产生函数和关于事件接收线程优先级信息的指针。
每一第二实体由一个或者多个第一实体所指,并保持指向一个事件接收线程的指针,以便传递分发给它的事件消息。
第二实体的第三实体表指向事件接收线程。
每一事件产生函数保持一个指向事件处理函数的指针用以传递事件。
其它具有优点的实施例来自权利要求6-28。
附图的简要说明现在参考附图详细叙述本发明,附图中

图1是一个线程执行的示意图;图2是线程执行的状态转换图;图3是在一个远程通信实例中断开进程的示意图;
图4-7表示图形编程语言中所用的符号,用以标识事件的各种处理情形;图8示出在线程之间通过对象方法调用和事件进行的间接通信;图9示出线程之间通过事件进行的直接通信;图10用使用图形语言符号的视图说明在执行一个进程期间在本地事件队列中的缓冲事件;图11是一个常规的视图,示出和图10同样的情形,但表示出自身包含有单元和消息的进程;图12表示本发明所根据的一个事件机构的中央数据结构;图13-18表示用于图12的视图中的对象类的数据结构;图19和20表示两个位阵列。
实施例的详细说明在实现一个面向对象的远程通信应用时,将其分成一个表示系统资源(象信道、音调发送器等)和执行应用控制功能的控制逻辑的对象模型是适宜的。控制逻辑进一步分成独立的活动象呼叫控制、载体连接控制等等,因而具有不少优点。
应用的执行环境是进程。这里进程一词指的是打算用于一定活动例如一个电话呼叫的运行期环境。进程环境完全位于一个确定的处理器内并包括存储器(堆、堆栈)和执行能力。在进程中伪同时执行线程。进程也包含对象模型。
线程是控制逻辑的执行资源。线程的执行是由对象模型产生的事件驱动的。同一事件可能激发几个线程,然后它以线程优先级次序分发。事件通常作为对外部事件例如对一个由进程接收到的信令消息的响应而产生。
线程可以监视从某个特定的对象来的个别事件,监视从某个对象来的任何事件,监视从一类对象来的个别事件,或者监视从一类对象来的任何事件。一个线程维护它自己的上下文,亦即堆栈和处理器寄存器,但与其它线程共享堆。
线程对于把复杂的活动分成相对独立的子活动提供强有力的支持。线程中逻辑的执行,要么直到它进入需要一个事件继续的状态,要么直到完成它的执行。当一个线程进入等待状态或者完成了它的执行时,则给其它线程执行的可能性。这意味着所有非同步事件在控制逻辑准备好处理它们时被交付给控制逻辑。
对象模型用作对应用必需的实际对象例如一个ISDN用户的终端、一个连接、一个用户等的抽象。对象通过方法调用--例如由一个连接对象提供的方法“连接”为控制逻辑提供服务。对象封装有数据,由此维护它自己的状态。对象也可以通过发送消息给其它进程和从其它进程接收消息而与进程之外的世界通信。
此间作为一个例子假定,线程特别设计用来支持用主要具有图形句法的特别图形编程语言编码的程序所使用的对象语义(objectsemantics),虽然也可以编写用C++编码的程序来符合这些语义。
作为上述的一个例子,图1表示有两个线程104和106的一个进程102,它们作为各个控制逻辑的执行资源。线程104和106的执行分别由事件108和110驱动,事件108和110由在进程中的对象逻辑产生并由属于各线程104和106的一个本地事件队列112和114管理。进程由一个存取中介对象118从一个存取进程(未示出)正在接收的消息116启动。作为结果,存储中介对象118产生事件108,它被发送到线程104启动该线程的执行。线程104的执行控制逻辑对一个对象122执行一个方法调用120,作为结果它又产生事件110,其被发送到线程106,启动该线程的执行。
图2表示线程执行的一个状态转变图。开始和结束状态未示出,但在下面会出现。
一个新的线程在产生时不会立即开始执行,而是在一个“等待启动事件状态”202等待一个邮寄给自己的启动事件。在接收到由箭头204指示的启动事件时线程执行开始,由“执行”状态206指示。在执行时,该线程可能进入一个等待状态,等待某个或某些事件发生。
事实上,线程是否进入等待状态依赖于等待的事件是否已经发生。如果它已经发生,线程将继续执行,尽管它将进入(由箭头208指示)一个“具有缓冲的执行”(execution-with-buffered)状态210,同时等待发生的事件,由箭头212指示。否则,也就是说,如果事件尚未发生,则进入一个或者两个等待状态218或者220。状态214“等待事件”用于等待单一事件。分别在216和218指示转移箭头“等待事件”和“接收等待的事件”。状态216“等待任何事件”用于等待任何事件。分别在222和224指示转移箭头“等待任何事件”和“接收等待的事件”。具有两个等待状态的原因是当该线程将要被再次启动时,作为一个已发生事件的结果,在把该事件与本地事件队列匹配时该线程使用不同的策略如果在等待任何事件,则事件总是匹配,否则必须对全体本地事件队列进行检索。如果存在匹配,则线程将再次开始执行,进入“执行”状态206。
当在状态210“具有缓中的执行”,该线程可能等待某一事件发生。如果这一事件已经发生(可在本地事件队列中找到),则这一执行在同一状态中立即继续,否则该线程进入等待状态214或者216当中的一个。
图2中没有结束状态,但是当线程的主函数返回时到达结束状态。对于主函数返回,线程必须被执行,因此既可能从“执行”状态206也可能从“具有缓冲的执行”状态212转移到结束状态。
在每一个感兴趣的线程接收到事件并有机会处理它们之前一定不能删除这些事件。决定何时发生这种情形的问题由在事件和线程模块之间的协调而解决。总的说来,是事件自身在被分发到所有感兴趣的线程之后删除自己的,但是,既然一个线程并非总是在接收时立即处理一个事件,必需采取措施以防止事件在分发后被直接删除。这种情形发生在当一个线程接收到一个并非当前等待的事件时。仅在等待并处理了一个事件之后,它才可以被删除。
使用一个引用计数器来跟踪对存在的事件有多少引用。当计数器减到0时,事件删除自身。当一个接收到的事件在一个线程内被缓冲存储时计数器增量,当线程等待到一个缓中存储的事件并到达一个新的等待状态或者消亡时计数器减小。当线程消亡时,所有缓冲存储的事件的引用计数器必须减小。后面连同对事件方框的更详细的说明一起继续进行有关此点的进一步说明。
至于对象的交互作用,“线程”类管理在两个执行线程的上下文,亦即当前线程上下文和该线程自己的上下文,之间的切换。当线程收到一个等待的事件,则把当前线程上下文保存起来并切换到线程自己的线程上下文。当线程希望等待一个不在本地事件队列中的事件时,则给其它线程执行机会。
仅在接收到线程等待的一个事件时才切换到线程自己的线程上下文。因此执行一个特殊的过程启动线程。首先,一个线程构造器建立对特殊启动事件的监视。接着产生一个相应的事件并寄出。然后线程接收该事件,对待它象任何正常接收的事件,并承认它是线程正在等待的事件,从而启动线程的执行。
事件通过在一个特别的进程中发生一个内部或者外部事件(incident)时及时通知所有感兴趣的线程来协调线程的执行。这种事件的例子是一个呼叫(外部)的断开和超时(内部)。换句话说,事件函数支持用于在一个进程内通信的机构。
事件启动线程的执行。事件没有预先指定的接收者,而是分发到声明对特定事件感兴趣的线程上。由于事件函数,有可能独立地构造对象逻辑和控制逻辑。一个事件包含一个名字、发送者和携带从产生者到该线程的信息的相关数据,并仅存在于进程中。
事件由在一个进程中的对象产生,通常作为一个接收到的消息例如用户收线消息的结果。
事件的说明可以借助于图形语言和设计语言的结合而进行。如前所述,控制逻辑由图形语言的流程图说明,而形成对象逻辑的对象可以以一种设计语言用一个对象类型说明或者类说明来说明。
事件管理具有如下的一些特征-事件分发到所有监视它的线程。在一个进程中产生的所有事件结束在一个公共的“信箱”即前面提到的“事件处理器”中,从该信箱它们又被进一步送到所有曾经指出对这些事件感兴趣的线程。如果没有一个线程对这些特定的事件感兴趣,则将其抛弃。这些兴趣的指示,亦即对事件监视的顺序必须在流程图中明确标出;-当一个事件被分发到对这一特定事件感兴趣的监视线程时,该线程也许尚未准备好处理它。如果执行尚未到达等待这一事件的状态或者如果另一个线程此时正在执行,就可能是这种情况。于是该事件被放到属于该线程的队列中,参见图1中的本地事件队列112和114。当线程准备处理该事件时,它从本地事件队列中取出该事件,然后执行将继续,直到需要一个新的事件来决定怎样进行。这一事件可以是另一个外部事件或者像超时这样的内部事件,参见图1中的事件108和110;-广播/主动接收。从事件产生者的观点看来,一个事件不可能导向一个指定的接收者。所有产生的事件都分发到所有监视该事件的线程,包括发送线程。这一概念意味着,产生这些事件的实体不知道对事件感兴趣的实体。接收者决定什么时候等待和等待什么(“主动接收”)-执行以伪并行方式进行。线程以伪并行方式执行,亦即一次一个执行。线程中每次执行开始于接收到该线程等待的事件,之后线程不受干扰继续执行,直到需要再次等待或者完成执行为止。此时可以执行由同一事件或者另外的事件激发的另一线程。上面所述例如对在图1中的线程104和106来说就是如此。
事件是按照它们邮寄的次序分发给线程的。但是,由于单一事件可以分发到多个线程,因此这些线程具有一个优先级来指明在这种情况下的次序。线程也可能阻止接收到的事件进一步分发,阻止低优先级线程接收到该事件。
对于一个能够接收事件的线程来说,该线程必须明确在事件邮寄之前已经监视了它。通过监视,线程声明它对来自某个(或某些)对象的事件的兴趣。如果监视是在事件被邮寄之前进行的,则这种监视使该事件(或这些事件)被分发到所述线程。线程也可能解除一个已经进行的监视,从而阻止所述事件(或这些事件)进一步分发给该线程。
图3表示在进程302中执行的“断开”。“断开”由一个来自访问进程(未示出)的断开消息304启动。一个访问中介306的对象逻辑作为结果会通过事件308激发其中正在执行某一断开控制逻辑的线程310。这一逻辑通过请求一个要建立的定时对象的实例314而启动一个定时函数(由箭头312所示)。
然后,线程310的控制逻辑的执行中止以等待一个可能为超时或者从外部世界来的另一消息的新事件。在上述例子中,实例314接收到一个超时消息316,它发送一个“超时”事件到线程310,超时事件再次启动线程310执行功能逻辑而分别给“调用”对象322和“远程通话”对象324产生拆线消息318和320。
事件处理机构提供下述服务。
-邮寄事件。定义为事件产生的对象能够发送所产生的事件。当一个事件作为一个内部或者外部事件例如用户挂机或者解除一个时间监视的结果而产生时就出现这种典型的情形。
-监视事件。一个事件接收线程可能声明对它希望接收的一定事件感兴趣。在一个特定的预订命令中声明是对一个特定的事件还是对由一定线程产生的所有可能的事件感兴趣。当或如果这一事件被产生并被发出,它将到达预定该事件的接收线程。
-取消事件的监视。不再对一个事件感兴趣的线程可以取消它对该事件的监视。
-阻止事件的进一步分发。一个线程可能在接收一个事件后阻止该事件进一步分发。通过“杀死”该事件,尚未接收到该事件的线程将永远不能执行它。
下面详细说明每一服务。
邮寄一个事件意味着把一个产生的事件送往一个中心对象,即事件处理器,后者把它分发到感兴趣的线程。如前所述,事件是作为外部或者内部事件的结果而产生。外部事件通常作为消息报告给进程,这些消息反过来又由在进程内的事件产生者传输给事件。当事件在晚些时候被分发时,其以邮寄时的次序进行。
邮寄事件的图形编程语言的句法例如可能包括一个在图4中的邮寄事件的符号。所有监视该事件的等待线程将接收它。如图所示,这一符号包括被发送的事件的名字。符号输入参数数据也可能与该事件一起邮寄,这在后面另外叙述。该符号有一个无结果值的出口,并直接指向下一要执行的节点。
从语义学的观点来说,被执行的线程例如也可能产生“EventName”(“事件名”)事件。该事件连同包含的数据一起邮寄到所有等待它的线程。如前所述,该事件不能邮寄给一个特定的线程。
对特定事件感兴趣的所有线程必须通过预定监视这些事件指明它们的兴趣,亦即声明事件接收者对一个特定事件的兴趣。产生一个包含唯一标识该事件的数据的监视器对象来实现监视。换句话说,监视器对象表示事件接收者声明对事件的兴趣。图形编程语言中的句法例如可能使用图5中带一个竖直黑旗的菱形符号指定开始监视事件。在该符号中总是有所指定的至少一个发送者和一个事件。
分别示于图4和图5、并在上面叙述的两个符号中的每一个符号仅有一个指向下一要执行的节点的输出箭头,该箭头上不附有结果值。
根据希望监视的事件数目以及事件起源的不同发送者的数目,有四种指定“开始监视事件”的可能性,它们是-监视从一个确定的发送者发送的一个事件;-监视从一个确定的发送者发送的任何事件;-监视从一组发送者发送的一个事件;-监视从一组发送者发送的任何事件。
从语义学的观点来说应该注意,当在一个流程中执行用于开始监视的符号时,所有指定事件的实例只要发生就将分配到该流程中。这些事件然后排在该线程的本地事件队列中直到它们被该流程发送出去。
监视从一组发送者发送的一个事件意味着,如果该组发送者的任何实例邮寄这一事件,则它被交付到接收者。
如前所述,需要从一个对象或者其它线程得到某一信息以便处理的线程可以把自己置于等待状态。从而该线程的执行中止而其它线程开始运行。在以事件的形式接收到希望的信息,并直到当前活动的线程停止执行后,该线程才执行恢复。
图6示出在一个以图形编程语言表示的流程中的等待状态。等待状态自身用一个椭圆符号602表示,从该椭圆引出的箭头604、606、608和610指向符号612.1、612.2、...、612.n。这些符号指示不同的发送者,而在每一个符号下面的箭头指示该线程(流程)正在从各发送者等待的事件。从图6可以看出,分别用ev1,ev2、ev3;ev4、ev5和ev8、ev9指示各发送者612.1、612.2和612.n的这些事件。符号中包含有发送者的名字。如下所述,也可以使用包含星号的符号。等待状态可以有一个名字。它也可以有与之相关的一个条件表。
当流程的执行到达等待状态时,首先测试条件表(如果有的话)。如果条件不匹配,则产生一个错误。如果条件满足,或者没有任何条件表,则停止执行,因为已经到达一个等待状态。在从发送者接收到与其联系的事件后恢复执行。然后执行沿着由所发生的事件命名的箭头进行。
可以使用下述事项作为发送者的名字-指向一个对象实例的一个变量,该事件必须来自给定的对象实例,以恢复执行。
-线程标识,这些事件必须来自给定的线程实例,以恢复执行。
-星号(*),它表示对所陈述的任何事件都感兴趣,而不管产生该事件的是哪一个对象或者哪一个线程。
如果事件接收者对事件不再感兴趣的话,先前进行的监视可以清除。通过删除在事件接收者早些时候声明对事件感兴趣时产生的监视对象,清除对事件的监视。
在编程语言中,中止监视事件例如可以用在图7中示出的符号表示。如图所示,该符号与图5中的不同,它有一个放倒的旗子。该符号至少总有一个发送者和一个事件。该符号只有一个指向下一个要执行的节点的外向箭头,没有结果值附在该箭头上。当在一个流程中执行该中止监视符号时,指定事件的实例将不再由该流程接收。
只有一个事件是预先定义的,即“DEATH”(“死亡”)事件,它在一个事件产生对象被删除时自动产生。可以象其它任何事件一样监视和接收事件“DEATH”(“死亡”),但它不带有任何数据。在参考这一事件时应该使用关键词DEATH(死亡)。
线程之间的通信有几种可能。一种是通过对象方法调用的通信。当对象执行一定的方法时,它们可以产生事件。然后把这些事件送往所有感兴趣的线程。这一点用图8的例子说明。线程802对一个对象806发送一个方法调用(箭头804)。接着对象806给另一线程810发送事件808。以这种方式可以进行两线程之间的通信。通过用适当的方式结合这些机构可以使两个线程“彼此对话”。
流程自身,亦即线程,也可以产生事件。这意味着两个(或者更多)线程可以通过彼此发送事件和从对方彼此接收事件而直接对话。这用图9的例子说明,在该例子中线程902给另一线程906发送事件904。注意,虽然这一简化了的图似乎说明在线程之间直接交付事件,但实际并不是这种情况。这些事件是通过一个事件处理器分配的,图中未示出。
现在参考图10和图11,图10表示在进程中出现的流程图,图11表示用1102指示的进程以及它的一些单元。被监视的事件可以由一个线程缓冲存储到一个本地事件队列中。缓冲存储指的是在一个事件被监视后,它的任何出现均可被观察到,而在监视发出之前发生的事件则不可使用。如果对一个事件不再希望的话,则清除对其进行的监视。已经接收到的事件留在本地事件队列中,直到它们被“等到”,此时允许该线程继续执行。如果当线程等待时事件尚未发生,线程的执行将空运行,直到该事件发生。
在图10中,1002指示开始,作为图11的进程1102的第一步,监视一个事件e1,该事件的源是一个事件产生者EG1。在1004指示开始监视由事件产生者EG2产生的事件e2。图11指示事件产生者EG1和EG2分别包含在进程1102中的1104和1106处。进程1102还包括一个具有本地事件队列1110的线程1108。
在图10中,1006表示一个等待状态,这里中止执行而等待e2的出现。在1008指示事件e1现在从事件产生者EG1产生,其由在图11中的箭头1112指示事件e1被缓冲存储到本地事件队列1110中。在图10的1010处指示事件e2现在从事件产生者EG2发生,并在1012指示开始对其执行。
图10中的符号1014表示中止执行等待事件e1。在1016指示该事件已经发生并已开始执行。
现在参考图12更加详细地说明安排事件驱动程序线程的方法。在说明中使用对象类这一概念,对象类包含在一个特别的类结构中。下面相继对这些类在其名字出现时详细说明。
图12中的框1202-1206指示事件处理机构的中央服务类EventHandler(事件处理器)的一个基类EventGenerator(事件产生者)的各对象事件产生者、以便进一步分发,其中基类的对象可以给事件处理器对象邮寄事件。框1208-1212指示一个通过继承能够接收事件对象的抽象基类EventReceiver(事件接收者)的各对象事件接收者(线程)。
一个以类命名的事件代表一个进程事件。一个事件对象由一个标签和一个源(事件产生者)唯一定义。每一个事件产生者是一个类DistCat的某一分发类型的成员,从而使对一组事件产生者的监视成为可能。参考图13,EventGenerator使用下述对象实现-EventHandler,用于传递事件的邮寄和声明建立和解除产生者;-DistCat,表示某一分发类型中的成员;-MonItem,表示跟踪对所有由产生者产生的事件的监视;作为接口,EventGenerator使用Event邮寄事件。
EventHandler是中心类,在这里维护跟踪所有监视的结构、事件产生者和事件接收者。
参考图14,EventHandler使用下述对象类实现-MonItem跟踪对单个事件产生者的所有监视;-DistCatNode跟踪哪一事件产生者属于哪一个分发类型,该节点被保存在二进制树中;-Event保存事件到分发时间,然后交付它们到接收者;-ErItem跟踪所有对分发类型的监视;-DeadErList跟踪哪一个事件接收者被清除;-Memory用于分配内部对象。
作为接口,EventHandler使用下述对象类-DistCat用于登记对分发类型的监视;-EventReceiver用于登记监视;-EventGenerator用于登记对单个事件产生者的监视。
EventReceiver是一个抽象基类,它通过继承给它的派生类添加接收事件的可能性。线程从EventReceiver导出。
参考图15,EventReceiver使用类EventHandler实现交付建立和清除接收者的标志。
作为接口EventReceiver使用类Event,它被交付给从接收者导出的类。
回到图12,框1214指示一个对象DistCatNode(分发类型节点),它是二进制树DistCatTree中的一个节点。DistCatTree包含一个ErItem(事件接收者登记项)类的对象表。该类用于跟踪分发类型的监视。每一对象ErItem维持一个指向一个事件接收者的指针并将被分发的事件传递给它。框1216-1220指示各ErItem对象具有各自指向事件接收者1208-1212之一的指针1222-1226。
DistCatNode跟踪一个分发类型的所有事件接收者。参考图16,DistCatNode继承BinTreeNode,从而具有作为由事件处理器快速查找的二进制树的成员的属性。DistCatNode使用DistCat记载分发类型,使用ErItem跟踪同一分发类型的所有事件接收者的环(被监视的每一事件接收者由在内部结构中的一个ErItem代表)。上面出现的词“环”(ring)还会在下面出现,它用于表征一个相关联的实体表,例如刚才提到的事件接收者,其中表指针的最后一个实体返回到表的第一个实体。称为环的原因基于这一事实,在图12中所示的实施例中作为一个例子建立这一类型的表。然而所讨论的表不必采取链结的环的形式。
参考图17,类ErItem是在内部结构中一个被监视的事件接收者的表示。它跟踪对其事件由事件接收者接收的分发类型的监视。它还保持对一个其事件由事件接收者接收的单个事件产生者(由MonItems表示)进行的所有监视的环。
ErItem继承RingLink,使得同一分发类型的所有ErItem可以连接在一起。
ErItem使用下列类实现-EventReceiver用于传递receiveEvent(接收事件)和handleDeadlock(处理死锁)函数调用;-MonItem,用于保持为所讨论的接收者对单个事件产生者进行的所有监视的环;-DistCatNode,在ErItem被清除时以便将其从ErItems的DistCatNodes环上拆除;-Memory,使ErItem正确返回占用的存储器;-EventTag,当将出现的标志与监视相比时和在更新和“恢复”(downdating)监视时使用;
作为接口,ErItem使用Event,后者在分发该事件时传递到相应的事件接收者。
返回图12,每一个ErItem对象还保持一个MonItem(监视事项)类的对象表。该类用于跟踪单个事件产生者的监视。块1228-1238指示各个MonItem对象。
参考图18,MonItem是对单个事件产生者监视的内部表示。
MonItem继承-ErMonLink,以便能够成为ErItem保持其事件接收者的所有单个监视的环的成员;-EgMonLink,以便能够成为MonItems的事件产生者环(亦即对该事件所进行的所有单个监视构成的环)的成员。
MonItem使用下述类实现-ErItem,用以保持指向ErItem的一个指针,后者保持指向事件接收者的指针;-EventTag,当将出现的事件标志与监视相比时和当在更新和“复原”监视时使用;-Memory,以便ErItem正确返回占用的存储器。
返回图12,可以通过DistCatTree到达所有的ErItem。树中包含的每一个DistCatNode对象例如对象1214包含一个所有ErItems的环,例如对象1216-1220,它们是为表示对诸如对象1202-1206等单个事件发生者或者对分发类型的监视而产生的。在图12中,该环由把ErItem对象1216-1220连接在一起的箭头1240、1242和1244表示。一个DistCatNode环中所有的ErItems是对同一分发类型的事件产生者的监视的结果。
总的说来,ErItems连接成环,而每一个环属于某一DistCatNode。该环按照接收者的优先级排序。当对一个先前未进行监视的事件接收者建立监视时产生一个ErItem。然后该ErItem连接到属于DistCatNode的ErItems的环,该DistCatNode对应于这一监视的事件产生者的分发类型。
ErItem自身有一个指针(参见指针1222-1226),指向相应的事件接收者(参见事件接收者1208-1212)以传递receiveEvent(接收事件)和handleDeadlock(处理死锁)函数调用。另外,每一ErItem有一个指向DistCatNode(参见节点1214)的指针,以快速从DistCatNode环上拆除ErItems。在图12中,这样的指针由从ErItems 1216-1220的每一个出发的一个公共箭头1246表示。每一个ErItem还有一个MonItems环的成员。对于ErItem1216,这样的环包含MonItems 1228-1232,并由箭头1248-1252表示。对于ErItem1218,该环包含MonItems 1234和1236并由箭头1254和1256表示。ErItem 1220的“环”包含单一MonItem 1238并由箭头1258表示。
每一个MonItems 1228-1238表示对一个个别事件产生者的监视。于是,MonItems 1228、1234和1238表示对由从MonItems 1228、1234、1238中的每一个引出的一个箭头1260指示的事件产生者1202的监视。同样,MonItems 1230和1236指示对由从MonItems 1230和1236每一个引出的箭头1262表示的事件发生者1202的监视,而MonItem 1232表示对由箭头1264指示的事件发生者1206的监视。在每一场合,监视事件接收者是由ErItem指向的。于是对于MonItems 1228、1230和1232,ErItem 1216指向事件接收者1208,对于MonItems 1234和1236,ErItem 1218指向事件接收者1210,而对于MonItem 1238,ErItem 1220指向事件接收者1212。这些ErItems保持各自的MonItems环(它是无序的)以保证当事件接收者消亡时恰当清除所有监视。
ErItem还跟踪分发类型的所有监视。下面说明它的做法。
ErItems是从快速存储器(由Memory类管理)分配的对象,因此它们也保持一个指向它们由之分配、而当它们被清除时应该返回的存储器的指针。
每一事件产生者,例如事件产生者1202-1206,保持一个MonItems的环,这里环中的每一个链相应于对作为事件源的事件产生者的监视。于是,对于事件产生者1202,MonItems 1228、1234和1238包含在一个由箭头1266、1268和1270指示的环中。对于事件发生者1204,MonItems 1230和1236包含在一个由箭头1272和1274指示的环中。对于事件产生者1206,MonItem 1232包含在由箭头1276指示的一个“环”中。
每一个事件产生者还保持一个指向事件处理器的一个指针,用以传递事件的邮寄。另外,它有一个指示该事件产生者所属的分发类型的DistCat类型的成员。
如上所述,一个MonItem代表一个或者多个为一个事件产生者对于某个事件接收者进行的监视。同样可见,一个MonItem是两个环的成员,一个环(按照接收者的优先级排序)属于该事件产生者,另一个环(无序)属于相应于监视事件接收者的ErItem。于是,作为一个例子,MonItem 1228是属于事件产生者1202的环1266、1268、1270的成员,也是属于相应于事件接收者1208的ErItem1216的环1248、1250、1252的成员。
每一个MonItem保持一个指向它的ErItem的指针以快速从ErItems环拆除MonItems和在建立分发表寻找事件接收者。于是,MonItems 1228、1230和1232保持指向ErItem 1216的指针,由一个公共的箭头1278指示。MonItems 1234和1236保持指向ErItem 1218的指针,由一个公共箭头1280指示,而MonItem1238保持指向ErItem 1220的一个指针,由箭头1282指示。每一个MonItem也包含一个分别由箭头1260、1262和1264指示的分别指向事件产生者1202、1204和1206的指针,以快速从该产生者的环上拆除MonItems。为快速建立分发表,它们还包含被监视的事件接收者的优先级。
MonItems是从快速存储器(由Memory类管理)分配的对象,因此它们也保持一个指向它们由之分配并在它们被拆除时返回的存储器的指针。
一个MonItem表示一个或者多个对从一个产生者到一个接收者的事件进行的监视。为跟踪MonItem表示多少监视,它包含一个引用计数器。
事件处理器是事件管理机构的中心对象,事件管理机构维护跟踪所有监视的结构。DistCatTree是事件处理器的一个成员,它由事件处理器用于在建立一个监视时寻找相应于一个事件产生者或者一个分发类型的ErItem。如果找不到一个ErItem,则事件处理器产生一个,并将其插入DistCatTree中。
事件处理器保持一个所有邮寄的但是尚未分发的所有事件的一个环,也就是说事件正等待分发到事件接收者。当一个事件接收者消亡,则它不能接收事件。因此,为该接收者建立的MonItems不再有用处。但是它们不能被删除,因为可能还存在指向该MonItem的监视对象。这些MonItems被移到一个“死亡”MonItems的表中,在每一次任务结束时扫描该表,当MonItems的引用计数为零时,将其拆链并删除。
对于ErItems,在其接收者死亡时情况几乎一样。不能立即消除ErItems,因为用户也许有监视对象引用该ErItem。也可能存在有引用该ErItem的分发表。为解决分发表的问题,当接收者死亡时把指向接收者的ErItems指针置为0,然后该ErItem不再传递任何事件到接收者。在每一任务结束时,把所有接收者指针等于零的ErItems移到一个“死亡”ErItems表中。在每一任务结束时扫描该表,当ErItems的引用计数为零时将其拆链并删除。
事件对象是发生的、交付给事件接收者的事件的软件描述。一个事件保持一个指向寄出该事件的事件产生者的指针和一个包含DistItems的分发表。当事件被寄出时建立该分发表,且每一DistItem包含一个指向ErItem的指针。分发表按照ErItems事件接收者的优先级排序。每一事件还包含一个事件标签。
在每一事件寄出时为其建立一个分发表。分发表由事件处理器建立,它扫描内部结构,寻找与事件的事件标签匹配的MonItems和ErItems。分发表是一个单线联系的DistItems表,每一个DistItem包含有指向一个ErItem的指针,而ErItem接着把事件传递给等待分发的事件接收者。
为建立分发表,应该寻找相应于邮寄事件的事件产生者的分发类型的ErItems环。该环由在DistCatTree中的一个节点保持。如果找不到环,则说明没有对该事件进行监视,从而它可以舍弃(删除)。
另外,需要一个MonItems的环表示对事件产生者所进行的监视。该环由这一事件产生者保持。
下面分别把这两个环叫作er环和mon环,它们接着被扫描,其成员与邮寄事件的标签相匹配,同时这两个环均按照事件接收者的优先级排序。
从扫描mon环查找匹配的MonItem开始扫描。在找到一个匹配的MonItem时,遍查er环直到由该MonItem指向一个当前的ErItem为止。与此同时,收集所有匹配的ErItems形成分发表。然后把由这一MonItem指向的ErItem放在分发表上,同时er环指针升一级以避免该事件给接收者分发两次。重复上述过程直到两个环完全被扫描。现在完成了分发表,将其交付给事件。
每一个被邮寄的事件放在一个环上等待分发。分发自身非常简单,因为每一事件携带它自己的分发表,所以分发缩减为下述步骤。对事件环上的每一个事件,清除该事件并将其分发到它的分发表上的所有接收者。在每一事件交付之间,检查eventKilled(事件清除)标志,确定是否最后的接收者通过一个killEvent(中止事件)已经停止分发,在这一情形下用下一事件继续分发。
如上所述,ErItems跟踪对分发类型的监视,而MonItems跟踪对单个事件产生者的监视。这是通过保持一个每一位对应一个事件标签的位阵列做到的。监视产生时将这些位置位,监视清除时这些位清零。事件标签由称为“部分”和“索引”的两个分量组成,部分指示位矩阵的部分(参见图19的0、1、2、3),而索引指示相应部分的哪一位被置位。
例如,事件标签(0,9)、(0,257)和(2,65)与图19的位阵列匹配。
注意,事件标签的索引分量的最低有效位总是被置位,这是因为所有事件的监视必须总是匹配。例如,如果对图19的位阵列加一个对所有事件的监视,则所有部分的最后一位将被置位,参见图20。
因此在构成事件的事件标签时必须小心从序列(0,5),(0,9),...(0,231+1),(1,3),(1,5),...(1,231+1),(2,3),(2,5),...(2,231+1),(3,3),(3,5),...(3,231+1)中选择。然而,事件标签也可以使用构成因子构成,构成因子取一个整数作为参量,然后进行映射0->(0,5),1->(0,9),2->(0,17)等。还要注意,在0部分从右数第二位为预定death(“死亡”)事件标签亦即标志(0,3)预留。
为避免在每一个感兴趣的接收者处理事件之前删除该事件,引入一个处理机构。它是在事件机构和线程之间的一种合作。这一机构基于具有计数器的事件,该计数器由事件处理器和线程增减。当计数器递减到零,则事件删除自身。在从事件处理器的邮寄事件环中取下一个要分发的事件时块增加。在事件被分发到所有感兴趣的接收者后立即减小。如果没有线程增加该事件计数器,则该事件删除自身。
在一个事件接收者被清除时,不可能清除相应的ErItem,因为也许存在有指向它们的DistItems。还可能存在有指向它们的“监视”对象。当一个事件产生者被清除时,不可能删除它的MonItems表,因为也许存在指向它们的“监视”对象。
为解决这两种情况,有两个声明死亡的对象表,DeadErList和DeadMonItemList,这里死亡指的是该对象不再有用处,但是不一定能删除,因为它可能由某个其它的对象引用。DeadErList包含指向已失去其事件接收者的ErItems的指针,而DeadMonItemList是一个包含所有已失去其事件产生者、但仍然由某个(或某些)“监视”对象引用的MonItems的环。
在每一任务结束时进行一次清除,包括下述步骤。
首先,在MonItems的环中对在DeadErList中的每一个ErItem,删除每一个引用计数为零的MonItem,其余放在DeadMonItemList中;然后,遍历DeadMonItemList,同时拆链和删除引用计数为零的所有MonItems;最后,遍历DeadErList,同时拆链和删除引用计数为零的所有ErItems。
权利要求
1.一个管理一个进程中的内部执行线程的系统,执行线程,它由进程内部事件消息驱动,这些消息由事件产生函数(1202-1206)响应发生的内部或者外部事件产生,内部事件消息被分发到具有优先级的事件接收线程(1208-1212),由一个事件处理函数根据事件产生函数的分发类型控制分发,并只分发给对这样的内部消息感兴趣并对其出现进行监视的事件接收线程,对每一个分发类型有若干事件接收线程;若干第一实体(1228-1238),代表为一个事件发生函数对某个事件接收线程的一个或多个监视;若干第二实体(1216-1220),代表为事件发生函数对分发类型的监视,每一第二实体有一个所有第一实体(MonItem)的表,这些实体监视一个事件接收线程;一个第三实体(1214),使用一个第二实体(1216-1220)表跟踪监视分发类型的所有事件接收线程;若干事件发生函数,每一个保持一个第一实体(1228-1238)表。
2.根据权利要求1的系统,其中,每一第一实体保持一个指向事件发生函数的指针和维持关于事件接收线程优先级的信息。
3.根据权利要求1或者2的系统,其中,每一第二实体均由一个或者多个第一实体(1228-1238)所指向,同时保持指向一个事件接收线程的指针以便对其传递被分发的事件消息。
4.根据权利要求1-3中任何一个权利要求的系统,其中,第二实体(1216-1220)的第三实体表指向事件接收线程。
5.根据权利要求1-4中任何一个权利要求的系统,其中,每一个事件发生函数保持一个指向事件处理函数的指针以传递事件。
6.根据权利要求1-5的系统,其中,事件接收线程与各优先级指示关联,并且在进程执行期间,第二实体的第三实体表根据一个当前事件接收线程的优先级排序。
7.根据权利要求1-5或者6的系统,其中,在对一个先前尚未执行监视的一个事件接收线程建立监视时产生一个第二实体(1216-1220),然后第二实体(1216-1220)被引入一个属于第三实体(1214)的第二实体(1216-1220)表中。
8.根据权利要求1-5或者6或者7的系统,其中,每一第二实体有一个指向第三实体(1214)的指针以便能够从第二实体(1216-1220)的第三实体(1214)的表中快速清除。
9.根据权利要求1-5或者权利要求6-8中任何一个权利要求的系统,其中,保持指向第二实体(1216-1220)的第一实体(1228-1238)的指针,以便能够从第一实体(1228-1238)的第二实体(1216-1220)的表中快速清除以及寻找事件接收线程以便建立分发表,而指向一个事件发生函数的第一实体的指针允许从第一实体(1228-1238)事件发生函数的表中快速清除。
10.根据权利要求1-5或者权利要求6-9中任何一个权利要求的系统,其中,第一实体(1228-1238)是从快速存储器分配的对象,它们保持一个指向其由之分配并当它们被清除时返回的存储器的指针。
11.根据权利要求1-5或者权利要求6-10中任何一个权利要求的系统,其中,在建立一个监视时事件处理函数使用第三实体(1214)寻找相应于一个事件发生函数或一个分发类型的第二实体(1216-1220)。
12.根据权利要求1-5或者权利要求6-11中任何一个权利要求的系统,其中,事件处理函数保持一个所有邮寄但尚未分发的,亦即等待分发到事件接收线程的所有事件的事件表。
13.根据权利要求1-5或者权利要求6-12中任何一个权利要求的系统,其中,每一第一实体(1228-1238)包含一个引用计数,用以登记它所代表的监视。
14.根据权利要求13的系统,其中,一个第一实体(1228-1238)被移到一个不可用的第一实体表中,该表在进程中的一个任务结束时被扫描,此时,引用计数为零的第一实体(1228-1238)从表中清除并删除。
15.根据权利要求1-5或者权利要求6-14中任何一个权利要求的系统,其中,当事件接收线程不再可用且第二实体(1216-1220)不再给其传递任何事件时,第二实体指向该事件接收线程的指针置为0。
16.根据权利要求15的系统,其中,每一第二实体包含一个引用计数用以登记它所代表的监视。
17.根据权利要求15和16的系统,其中,在进程中的一个任务结束时,把指向事件接收线程的指针置为零的所有第二实体(1216-1220)移到一个不可用的第二实体(1216-1220)表中,该表在每一任务结束时被扫描,此时,引用计数为零的第二实体(1216-1220)从该表中清除并被删除。
18.根据权利要求1-5或者权利要求6-17中任何一个权利要求的系统,其中,第二实体(1216-1220)是从快速存储器分配的对象,它们保持一个指向它们由之分配并当它们被清除时返回的存储器的指针。
19.根据权利要求1-5或者权利要求6-18中任何一个权利要求的系统,其中,被交付给事件接收线程的已发生事件的软件描述(Event)的每一个保持一个指向从中寄出该事件的事件发生函数的指针,和一个包含代表把一个事件分发到一个事件接收线程的分发登记项(DistItem)的分发表。
20.根据权利要求19的系统,其中,当事件被邮寄时建立分发表,每一个分发项包含指向一个第二实体(1216-1220)的指针,且分发表按照第二实体(1216-1220)的事件接收线程的优先级排序。
21.根据权利要求19或20的系统,其中,每一事件表示包含一个表示事件类型的事件标签,而与哪一个事件发生函数可能邮寄它无关。
22.根据权利要求21的系统,其中,分发表是由事件处理函数扫描进程的内部结构,寻找匹配事件的事件标签的第一实体(1228-1238)和第二实体(1216-1220)而建立的。
23.根据权利要求21或者22的系统,其中,使用一个位阵列实现第二实体(1216-1220)跟踪对分发类型的监视和第一实体(1228-1238)跟踪对单个事件发生函数的监视,在该位阵列中,每一位相应于一个事件标签,在建立监视时这些位被置位,在监视完成时,这些位被清零,每一事件标签由两部分组成,一部分指示位阵列的一部分,另一部分是一个索引,指示在相应部分的哪一位被置位。
24.在根据权利要求1-5或者权利要求6-23中任何一个权利要求的系统中,为避免在每一个感兴趣的事件接收线程处理事件之前删除事件的方法,包括的步骤有使用事件处理函数和一个线程把相关于每一事件的一个计数器增量或减量,当计数器减到0时计数器删除自身,而当从所邮寄的事件处理函数的事件表中取下一分发的事件时计数器增量,而当该事件被分发到所有感兴趣的事件接收线程后立即减量。
25.在根据权利要求17-23中任何一个权利要求的系统中,为在每一任务结束后删除第一和第二实体的方法,包括的步骤有为在不可用的第二实体表(deadErList)中的每一第二实体(1216-1220)确定它的第一实体(1228-1238)表并删除引用计数为零的每一第一实体,引用计数不为零的放入不可用的第一实体表中;在不可用的第一实体表中确定所有引用计数为零的实体并将其从表中清除并删除;在不可用的第二实体表中确定所有引用计数为零的实体并将其从表中清除并删除。
26.在根据权利要求19-23中任何一个权利要求的系统中,为建立分发表的方法,包括的步骤有确定相应于邮寄事件的事件发生函数的分发类型的第二实体(1216-1220)表;确定表示对事件发生函数所进行的监视的第一实体(1228-1238)表;扫描如此确定的两个表,同时将其成员与所邮寄的事件的标签进行比较。
27.根据权利要求26的方法,其中,扫描包括下述步骤扫描第一实体表寻找匹配的第一实体(1228-1238),当找到时,扫描第二实体表以查找由找到的第一实体(1228-1238)指向的当前第二实体(1216-1220),同时收集所有匹配的第二实体(1216-1220)到分发表中,并对每一匹配实体将第二实体表的指针升高一级,以避免将该事件两次分发到事件接收线程;重复上述步骤,直到两个表完全扫描;把这样完成的分发表交给事件。
28.根据权利要求26或者27的方法,其中分发包括的步骤有把每一个所邮寄的事件放到一个等待分发的表中;清除该表中的每一个邮寄事件并将其分发到在该事件的分发表上的所有事件接收线程;在每一次事件交付之间检查最后的事件接收线程是否已经中止分发。
全文摘要
在一个管理进程中的内部执行线程的系统中,执行线程由进程内部事件消息驱动。这些消息根据事件发生函数的分发类型被分发到事件接收线程(1208-1212)并仅对对这些消息感兴趣且对其出现进行监视的事件接收线程执行。对于每一分发类型,存在若干相关的事件接收线程,若干表示一个或者多个为一个事件发生函数监视若干事件接收线程的第一实体(1228-1238),若干表示对分发类型的事件发生函数监视的第二实体(1216-1220),和一个跟踪所有监视这一分发类型的事件接收线程的第三实体(1214)。
文档编号G06F15/16GK1169192SQ9519668
公开日1997年12月31日 申请日期1995年12月8日 优先权日1994年12月9日
发明者M·沃尔夫 申请人:艾利森电话股份有限公司
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1