用于维护链接表的方法和装置的制作方法

文档序号:6558964阅读:195来源:国知局
专利名称:用于维护链接表的方法和装置的制作方法
技术领域
本发明涉及数字数据处理系统,特别涉及通常称为链接表(linkedlist)的软件数据结构。
现代计算机系统一般包括中央处理单元(CPU)以及存储、检索和传送信息所需的支持硬件,例如通信总线和存储器。它还包括需要与外界通信的硬件,例如输入/输出控制器或者存储控制器,以及所附加的设备,例如键盘、监视器、磁带驱动器、磁盘驱动器、连接到网络的通信线等等。CPU是该系统的心脏。它执行包括计算机程序的指令并且指示其它系统部件的操作。
从计算机硬件的观点来看,大多数系统基本上以相同的方式工作。处理器能够执行非常简单操作的有限集,例如算术、逻辑比较和从一个位置移到另外一个位置的数据移动。但是每个操作被非常迅速地执行。指示计算机执行大量的这些简单操作的程序使人产生错觉,认为计算机做了一些复杂的工作。
实际上计算机系统用于广泛的任务主要归功于指示计算机处理器的执行的丰富和大量的软件。多年来,软件已经进化和发展得更加复杂,就象硬件的发展一样。尽管特定的软件应用程序可能非常专用,但是它具有由本领域内的专业人员重复使用的特定共同技术和结构。软件得以改进的一个方法是改进那些共同使用的软件技术和结构,并且该软件的计算机系统是一个基本部分。
软件设计员意识到对数据结构的需要,即,以逻辑的方式安排数据,使得它可以被检索和操纵而不需要无用的工作。由软件应用程序所使用的数据结构是要在设计和开发应用程序中确定的其中一件首要事情。尽管可以创建几乎任何定制的数据结构,但是几种普通类型的数据结构被软件设计员重复地使用。其中一种最普遍的是链接表,其可以是单链接或双链接。
链接表是数据单元的集合,其中在该集合中的每个单元包含对该集合中的下一个单元的引用。单个单元除了该引用之外可能仅仅包含单个变量,或者可能是包含许多不同类型的数据的复杂数据结构,例如文本串、数字数据、指针等等,或者可能是除了该引用之外不包含任何东西的哑元。该引用一般是指向下一个列表单元的存储器地址的指针,但是它可以用阵列索引或一些其它数量的形式,从中可以推导出下一个单元的地址或其它位置。为了简单起见,在链接表单元中的引用在此称为“指针”,无论它直接指向地址或者间接索引如上文所述获得地址的参数。链接表单元的地址或其它存储引用不需要遵守任何排序,并且它可能把一个单元插入到链接表中或者从链接表中删除一个单元,而不需要重新分配在链接表中的所有或大量数目的单元。这仅仅需要改变相邻单元的指针。一个链接表可以是单链接,具有仅仅在一个方向上连接的正向指针,或者可以是双链接,具有正向和反向指针。
当在多任务环境中更新链接表时必须小心谨慎。如果多个同时执行的线程(thread)尝试同时改变相同的链接表,或者单个线程尝试改变该列表,而另一个线程遍历该列表,结果可能无法预测并且数据可能被破坏。该问题在单个CPU支持硬件多线程或者多个CPU同时执行多个线程的情况下特别严重,所有都访问一个共同的存储器。
在单链接表的情况下,在一些环境中可能通过使用特定类型的原子操作(atomic operation)而更新一个列表。但是,该方法不是在所有环境中可行,并且一般不用于双链接表,其需要更新在两个不同列表单元中的指针。一种一般被采用的更加普通的解决方案是锁定系统。需要更新一个链接表的任务一般获得在该列表的排它锁定,意味着其它任务被排除访问该列表,直到更新完成为止。需要遍历列表而不改变它的任务可能获得一个共享锁定,防止其它任务改变该列表而不需要防止遍历。
锁定(lock)的使用是简单而有效的,但是它具有影响性能的可能。可能需要一些时间来遍历一个列表,搜索特定的单元。在这段时间中,所有其它处理被排除改变该列表,并且根据锁定的类型,也可能排除遍历该列表。对于小的列表以及独立用于应用程序中的那些列表,这也许不是一个问题。但是可能有一些大的和经常被访问的列表,例如用于在操作系统中保持任务的状态的列表。这种列表的排它锁定可能变成一个性能瓶颈。这种瓶颈更可能出现在采用多CPU的系统中。
现在需要一种更新链接表而没有现有方法的缺点的方法,特别是一种在更少破坏在其它处理器中的任务执行的多处理器环境中更新包括双链接表在内的链接表的方法。
根据本发明,一种链接表具有相关的辅助数据结构,包括由更新任务所使用的对链接表的外部引用。辅助数据结构被用于防止链接表的子集被其它任务所改变,从而允许同时更新离散的子集。
在优选实施例中,链接表维持是使用面向对象(OO)编程技术来实现的。最好,该列表是双链接表。辅助数据结构是一种称为共享列表(SharedList)的对象,其中包括包含检查对象(inspector objects)和变元对象(mutator object)的迭代器对象(iterator object)、阻挡元对象(blocker object)和观察对象(view object)。迭代器对象被客户用来从外部访问链接表。检查对象是一种迭代器对象,其遍历该列表而不改变它;变元对象是一种迭代器对象,其改变该列表并且还遍历该列表。检查元(inspector)和变元具有相关的观察对象,该观察对象包含指向实际列表单元的指针。变元(但不是检查元)还具有相关的阻挡元对象,其阻止对所选择列表单元的访问。在操作中,变元对象通过改变指针使它们指向阻挡元对象而阻挡该链接表的一部分,阻挡元对象包含旁路(by-pass)被阻挡列表部分的附加指针。另一个检查元然后通过旁路部分遍历该列表,虽然遍历该列表的变元停留在被阻挡部位。
通过仅仅阻挡大的链接表的相对较小部分,多个任务可以同时访问不同的列表单元并且执行分离的列表更新,从而提高性能,特别是使用多处理器的情况下。特别地,在优选实施例中,与整个列表相反,通过在各个列表单元的级别上阻挡,多个变元可以同时遍历并且改变列表单元的不同部分,而不相互干涉,并且检查元可以同时遍利由一个或多个变元所改变的列表。
本发明的关于结构和操作的详细情况可以参照附图得到最好的理解,其中相同的参考标号表示相同的部件,其中

图1为根据本发明的优选实施例用于利用链接表数据结构的计算机系统的主要硬件部件的高阶方框图。
图2为根据优选实施例的计算机系统存储器102的主要软件部件的高阶示意图。
图3为根据优选实施例的链接表数据结构的高阶示意图。
图4示出根据优选实施例的在链接表数据结构中的对象类继承层级的外部示图。
图5示出根据优选实施例的各种外部和内部类与它们的继承层级之间的关系。
图6示出根据优选实施例的具有三个链接的一个示例SharedChain(共享链接)对象的简化示图。
图7示出根据优选实施例观察对象如何被用于引用一个链接列表中的单元。
图8示出根据优选实施例在SharedChain对象、阻挡元对象和链接之间的关系,示出已经阻挡一个链接的阻挡元对象的一个例子。
图9示出根据优选实施例用于阻挡把一个链接在两个其它链接之间的插入到链(chain)中所需的链接指针的变元的阻挡元对象的一个例子。
图10示出根据优选实施例用于阻挡从链中删除一个链接所需的链接指针的变元的阻挡元对象的一个例子。
图11示出根据优选实施例在多个观察对象和用于迭代变元的阻挡元对象之间的相互作用的一个例子。
系统概述参照附图,其中在几幅图中相同的参考标号表示相同的部件,图1示出根据本发明优选实施例,用于利用链接表数据结构的计算机系统100的主要硬件部件。中央处理单元(CPU)101A、101B、101C、101D对来自主存储器102的指令和数据执行基本机器处理功能。最好,每个处理器具有用于存储数据的相关缓冲存储器(cache)103A、103B、103C、103D,包括要由处理器所执行的指令。为了简单起见,CPU和缓冲存储器在此一般分别由参考标号101和103所表示。存储总线109在CPU101和存储器102之间传输数据。CPU101和存储器102还通过存储器总线109和总线接口105与系统输入/输出总线110进行通信。各种输入/输出处理单元(IOP)111-115附加到系统输入/输出总线110并且支持与各种存储和输入/输出设备的通信、例如直接存取存储设备(DASD)121-123,例如旋转磁盘驱动数据存储设备、磁带驱动器、工作站、打印机和用于与远程设备或其中计算机系统进行通信的远程通信线。
应当知道,图1被用作为系统配置的一个例子,并且在一个计算机系统中的部件的实际数目、类型和结构可能变化。特别地,本发明可以用于具有单个CPU的系统以及具有多个CPU的系统,并且CPU的数目可以变化。尽管各种总线如图1中所示,但是应当知道它们用于在概念上表示各种通信路径,并且总线的实际物理配置可能变化,并且实际上可能相当复杂。另外,尽管单个缓冲存储器103被示出与每个CPU101相关,但是在此可以由多级缓冲存储器,并且一些缓冲存储器可能专用于指令,而另一些专用于不可执行的数据,或者另外,可能根本没有缓冲存储器。在优选实施例中,计算机系统100是IBMAS/400计算机系统,应当知道还可以使用其它计算机系统。
图2为存储器102的主要软件部件的示意图。操作系统201提供各种低级软件功能,例如设备接口、多任务管理、内存分页管理等等,这是本领域内所公知的。在优选实施例中,操作系统201包括在IBMAS/400系统上正常执行操作系统功能的代码,包括有时称为“许可的内部代码”(“Licensed Internal Code”)以及OS/400操作系统代码,应当知道可以使用其它操作系统。数据库202概念上被示出为一个数据的一般集合,其上运行着应用程序。应当知道,可以使用各种类型的数据库,例如财务数据、表格和文本数据、图书馆数据、医疗数据等等。尽管在图2中示出单个示例性的数据库,但是计算机系统100可以包含多个数据库,或者可能没有包含数据库。应用程序203-205是通常通过访问数据库中的数据为用户执行特定工作的程序。例如,应用程序可以搜索和检索在数据库202中的数据、编辑数据、对数据执行复杂计算以产生附加数据,或者任何数目的其它应用程序。3个应用程序在图2中示出,应当知道应用程序的数目可以变化,并且一般远大于3个。
在操作系统201中,在数据库202内以及在应用程序203内具有链接表数据结构210、211、212。这些数据结构包含数据单元的链接表。这些数据单元,在此称为“链接”(“Links”),是列表的基本单元,该列表包含任意数目的这些单元。在优选实施例中,该列表是双链接表,因此每个单元或链接包含至少两个指针,一个指向下一个链接,并且另一个指向在该序列中的前一链接。链接可选包含附加指针,例如指向列表对象。它还可以仅仅使用单链接表,其中每个单元包含指向下一链接的正向指针,但是不包含指向前一链接的反向指针。在优选实施例中,每个链接表数据库210-212还包括用于访问和更新在链接表中的数据的辅助数据结构,如下文中更加详细地描述。
尽管特定数目和类型的软件实体在图2中示出,应当知道这些是仅仅用于解释说明的目的,并且这些实体的实际数目可以改变。特别地,为了说明该目的,链接表数据结构被示出驻留在操作系统201中、数据库202中以及应用程序203中,但是一些链接表数据结构可能仅仅驻留在操作系统中,或者仅仅在数据库中,或者可能存在于一个应用程序中,或者作为不是任何其它结构数据或程序的一部分的独立数据结构。另外,尽管图2的软件部件被概念地示出为驻留在内存中,但是应当知道一般计算机系统的内存太小而不能同时容纳所有程序和其它数据,并且该信息一般存储在数据存储器中,例如数据存储设备121-123,按照需要由操作系统从存储器分页(page)到内存中。
一般地,被执行以实现本发明的实施例的例程(routine),无论作为操作系统的一部分或者专用应用程序、程序、对象、模块或者指令序列的一部分,将被称为“计算机程序”。该计算机程序一般包括指令,该指令当由在构成本发明的计算机系统中的设备或系统的一个或多个处理器所读取和执行时,使得这些设备和系统执行需要执行步骤或产生体现本发明各个方面的单元的步骤。另外,尽管本发明已经并且在下文中将在完全功能的计算机系统环境中描述,但是本发明的各种实施例能够以各种形式作为程序产品而发布,并且本发明等同应用,而与用于实际执行发布的信号载体介质的特定类型无关。信号载体介质的例子包括可记录型介质,例如易失和非易失存储器件,软盘、硬盘、CD-ROM、DVD,磁带和传输型介质,例如数字和模拟通信链路,包括无线通信链路,但是不限于此。信号载体介质的例子在图1中示出为DASD 121-123和存储器102。
链接表结构外部接口在优选实施例中,相关软件数据结构和编程代码被使用面向对象(OO)编程技术而编写,但是应当知道还可以使用常规过程程序设计或者其它编程技术。在这下文的讨论中,使用OO技术,应当知道通常模拟数据结构、代码段或者其它实体被用于其它编程技术中。链接表数据结构210-212是称为SharedList的对象。
SharedList对象提供一种保持客户对象的双链接表的方法,但是具有一些独特的特征,即,(a)当链接被添加到列表中和/或从列表中删除时,客户可以安全地遍历通过该列表;以及(b)多个客户可以独立和同时从列表中添加或删除链接。SharedList对象使得所有客户同时访问列表。这在链接级上提供任务的阻挡,并且仅仅涉及在各个链接冲突中的那些任务在阻挡中涉及。SharedList<T>对象参照图3,其是链接表数据结构210、211的高阶示图,SharedList<T>类为任何类型T的客户对象的SharedList提供模板化支持。SharedList<T>对象301包含指向列表中的第一客户链接对象302和最后客户链接对象303的指针,以及在该列表中的链接数目的计数值(count)。它还包含在每个链接中的正向和反向指针的偏移量;该链接对象负责定义这些指针的字段(field)。
另外,每个链接可选地定义指向SharedList<T>对象本身的字段。如果该字段被定义,则当一个链接被插入到该列表中时,该指针被设置,并且当该链接被删除时,指针复位到NULL。根据他们的应用程序,客户可以通过查询该字段而使用指针来确定给定链接是否在一个列表中并且确定在哪个列表中。例如,用于一个客户对象的破坏器(destructor)可能要从该对象所在的列表中删除该对象。
图3示出如何查看SharedList<T>对象。在链接对象内的可选字段的偏移量是一个带符号整数,该偏移量指向SharedList<T>对象。在链接中指针字段的缺少由任何在偏移量字段中的负值所表示。SharedList<T>函数下文描述由SharedList<T>对象301所支持的主要函数void insertFirst(T*newLink)该函数在列表中插入特定链接做为第一链接。
void insertLast(T*newLink)该函数在列中插入特定链接做为最后链接。
void insertBeforeArbitraryLink(T*newLink,T*refLink)该函数插入紧接着在所引用任意链接之前的特定链接。一个任意链接是客户已知并且保证在列中,并且可以在列表中的任何位置的链接。
如下文中所述,可以遍历一个列表以定位链接的插入点或要被删除的链接,但是还可以跳转到列表的中部并且插入或删除任何链接,假如客户具有指向列表的中部中的链接的指针。
insertBeforeArbitraryLink函数是当客户具有这样一个指针时使用的几个函数中的一个。客户(或者一些外部机构)负责保证该链接确实在该列表中;如果没有的话,结果可能无法预测。
void insertAfterArbitraryLink(T*newLink,T*refLink)该函数紧接着在被引用任意链接之后插入特定链接。
T*removeFirstLink()该函数从列表中删除第一链接,并且返回一个指向它的指针。
T*removeLastLinkO该函数从列表中删除最后链接,并且反回一个指向它的指针。该函数需要该列表的原子观察(在下文中进一步描述),并且因此可能比在一些应用程序中希望的具有更多的限制。
void removeArbitraryLink(T*oldLink)该函数从列表中删除特定的任意链接。
T*removeBeforeArbitraryLink(T*refLink)该函数从列表中删除紧接着在特定任意链接之前的链接,并且返回一个指向它的指针。
该函数也需要该列表的原子观察(atomic view)。
T*removeAfterArbitraryLink(T*refLink)该函数从列表中删除紧接着在特定任意链接之后的链接,并且返回一个指向它的指针。
getLinkCount()const该函数返回在该列表上的链接的计数值的快照(snapshot)。它返回而没有任何同步。
下文的函数关于特定链接,即,假设客户已经有了一个链接的引用,但是不一定引用SharedList<T>对象301LinkStatus getLinkStatus(const T*refLink)const该函数返回特定链接的状态。如果该链接具有定义指向包含它们的SharedList<T>对象的指针的字段,则该函数表明特定链接是否在该列表中。如果该链接没有所定义的指针字段,则该函数仅仅表明它不知道该链接是否包含在该列表中。
static LinkStatus getbinkStatus(const T*refLink,int32 offset)const这是一个静态函数,其返回特定链接的状态。如果特定偏移量为负值,则该函数返回一个指示,表明它不知道该链接是否在SharedList<T>对象中。如果特定偏移量不是负值,则该函数返回一个指示,表明该链接是否在某SharedList<T>对象中。
static SharedList<T>*getSharedList(const T*refLink,int32 offset)这是一个静态函数,其返回指向包含特定链接的SharedList<T>对象。如果特定偏移量是负值,或者如果该链接没有在一个SharedList<T>对象中,则返回NULL指针
static SharedList<T>*removeArbitraryLink(T*refLink,int32 offset)这是一个静态函数,其从任何包含该链接的SharedList<T>对象中删除特定链接,并且返回一个指向该SharedList<T>对象的指针。
如果特定偏移量为负值,或者如果该链接没有在SharedList<T>对象中,则返回NULL指针(并且该链接没有被删除)所有上述插入或删除链接的函数产生迭代器对象的各种形式,以实际执行该函数。客户也可以使用迭代器对象(在此描述)来执行这些和其它函数。除了上述函数之外,各种次要函数可以被定义用于特定的应用程序,在此没有描述。应当知道上述功能列表仅作为一个实施例被描述,并且其它或附加功能可以与本发明相一致地定义。SharedListIterator<T>对象SharedListIterator<T>对象401提供遍历(“走过”)一个SharedList<T>对象301的链接,以及从该列表中插入或删除链接的能力。在此有各种类型的SharedListIterator<T>对象,并且它们以继承层级的方式排列。在此有仅仅可以通过遍历检查该列表的迭代器,和除了遍历之外还可以(通过插入或删除链接)对它进行改变(变化)的选代器;在此有具有列表的非原子观察的迭代器,和具有原子观察的选代器。为了对该列表进行工作,客户产生所需类型的迭代器,然后调用它所提供的函数。
如在此所用,原子观察意味着迭代器被确保没有其它变元(mutator)同时尝试改变该列表,即,该迭代器具有排它访问的形式,尽管它可以允许检查元(inspector)来同时访问该列表。非原子观察意味着在此没有这种保证。本发明的要点是允许对链接表的不同部位同时改动,并且相应地鼓励使用该非原子观察。但是,在一些形式的排它性为必要的情况下,提供原子观察,其在效果上类似于现有技术的锁定方法。迭代器的状态迭代器存在于如下状态中的一种无效(inactive)这是当创建迭代器时,一个迭代器的初始状态。在该状态中,不保持任何列表资源,并且不知道当前链接。当完成对列表的操作时,一个迭代器必须返回到该状态(或者当被破坏时隐含地返回该状态)。
有效(active)这是当迭代器保持列表资源并且得知当前链接时的状态。迭代器通常仅仅作为执行getFirstLink()(或者getLinkAfterArbitraryLink())方法的结果而到达该状态。但是,如下文中所述,有一些可以把迭代器转到有效状态的变元函数。
过渡(transition)该状态仅仅应用于变元。在该状态中,一个变元不再得知当前链接,但是仍然保持列表资源。因此,当到达该状态时,变元不应当被“置之不理”(“left alone”)。要使得insertBeforeCurrent Link()函数接续在一个列表末端。对象层级图4示出对象类继承层级以及由从SharedListIterator<T>对象类401继承的每个类所支持的功能的外部示图。这些对象类如下文所述SharedListIterator<T>401这是在继承层级中的最高类,并且它仅仅是一个抽象基类。它提供正向遍历该列表和在一个时间引用一个链接的能力。它是否具有改变该列表或仅仅检查该列表的能力由派生类所决定。它还具有该列表的原子或非原子观察,这也由派生类提供。
SharedListInspector<T>402这是从SharedListIterator<T>401派生的类。它也是一个抽象类。它只不过是一个迭代器,但是它保证不会改变列表。它具有由派生类所提供的列表的原子或非原子观察。
SharedListAtomicInspector<T>404这是一个从SharedListInspector<T>402派生的具体类。该类的对象具有列表的原子观察,这意味着它可以保证没有变元还处理该列表。该类的对象可以迭代通过该列表(正向或反向),但是不能改变它。
SharedListNonatomicInspector<T>405这是一个从SharedListInspector<T>402派生的具体类。该类的对象具有列表的非原子观察,这意味着变元可能同时处理该列表。该类的对象可以正向控代通过该列表,但是不能改变它。
SharedListMutator<T>403这是从SharedListIterator<T>401派生的类。它也是一个抽象类,但是它增加了通过在列表中插入或删除链接而改变该列表的能力。它具有由派生类所提供的列表的原子或非原子观察。
SharedListAtomicMutator<T>407这是一个从SharedListMutator<T>403派生的具体类。该类的对象具有列表的原子观察,这意味着它们可以保证没有其它变元来处理该列表。该类的对象可以正向或反向地迭代通过该列表,并且它们可以改变该列表。
SharedListNonatomicMutator<T>406这是一个从SharedListMutator<T>403派生的具体类。该类的对象具有列表的非原子观察,这意味着其它非原子变元还同时处理该列表。该列表对象可以正向迭代通过该列表,并且可以在该列表插入或删除链接。SaredListIterator<T>对象迭代器具有“走过”该列中的链接的能力。当在有效或过渡状态中,它具有一个当前链接,其是当前引用的链接。一个检查元保证当前链接不能被从列中删除。一个变元保证没有其它变元可以删除当前链接或在此之前的链接,也不能在它们之间插入另一个链接。
如下函数被提供于抽象基类中,用于所有类型的所有迭代器T*getFirstLink()该函数把迭代器的当前链接设置到在该列表中的第一链接,并且返回一个指向它的指针。作为该函数调用的结果,该迭代器处于有效状态。但是,如果在该列表中没有链接,则该所返回指针为NULL,并且如果它是一个检查元的话,则该迭代器处于无效状态,或者如果它是一个变元的话,则处于过渡状态。
T*getLinkAfterArbitraryLink(T*refLink)该函数把迭代器的当前链接设置到紧接着在指定的任意链接之后的链接,并且返回一个指向它的指针。作为该函数调用的结果,该迭代器将处于有效状态。但是,如果没有跟随在指定的任意链接之后的链接,则所返回指针为NULL,并且如果它是一个检查元的话,则该迭代器处于无效状态,或者如果它是一个变元的话,则处于过渡状态。
T*getNextLink()该函数把迭代器前进到该列表中的下一个链接。它把当前链接设置到该列表中的下一个链接,并且返回一个指向它的指针。但是,实际结果取决于在该函数被调用之前的迭代器的状态。如果该迭代器处于有效状态并且没有到达该列表的末端,则它将保持在有效状态。如果该迭代器处于有效状态并且到达列表的末端,则如果它是一个检查元,则将转到无效状态,并且如果它是一个变元,则将转到过渡状态;在任何情况中,将返回NULL指针。如果该迭代器处于过渡状态,则它将转到无效状态,并且将返回NULL指针。如果该迭代器处于无效状态,则它将保持在无效状态,并且返回NULL指针。
T*getCurrentLink()该函数返回一个指向迭代器的当前链接的指针。通常,该函数仅仅返回与用任何其它“getLink”函数的最近调用返回的数值相同的数值。但是,在此有一些变元函数,其可以使得变元的当前链接被改变,并且如果这种函数的结果表明变元的当前链接被改变,则该函数应当被调用以给出新的当前链接。
void reset()该函数把迭代器转到无效状态。它当迭代器的破坏器(destructor)运行时自动调用,但是它还可以由客户所调用,例如,把变元移出过渡状态。
IteratorState getState()const该函数返回迭代器的当前状态(有效、无效、或者过渡)。
getLinkCount()const该函数返回该列表中的链接数目的快照。
constructors(构造器)用于所有具体派生类的构造器要求一个与迭代器相关的SharedList<T>对象301的引用。另外,该构造器作为一个可选参数支持迭代器锁定在SharedList<T>对象上的范围的指示。该锁定可以被限于SharedListIterator<T>对象的存在,或者可以是动态的,仅仅当迭代器处于有效或过渡状态,或者(如果它是一个变元)当它执行一个改变函数时锁定。该动态选项使得迭代器可以在没有保持锁定在SharedList<T>对象“当不用于任何作用时”存在。当重复构造和破坏该迭代器的开销太大时,这可能是有用的。默认情况是该锁定限于该迭代器的使用期限。
destructor(破坏器)用于所有具体派生类的破坏器保证迭代器被复位到无效状态。SharedListInspector<T>对象该抽象类除了由SharedListIterator<T>基类所提供的函数之外不提供其它函数。从该类所派生的类的对象已知能够检查并且不改变该列表。SharedListAtomicInspector<T>对象这是从SharedListInspector<T>派生的具体类。该类的对象具有列表的原子观察。该列的对象可以正向或反向地迭代通过该列表,但是不改变它。
由于该原子观察,因此该类还提供如下函数T*getLastLink()该函数返回一个指向该列表中的最后链接的指针。除非在列表中没有链接,在该函数被调用之后,检查元将处于有效状态。在那种情况下,NULL指针将被返回,并且检查元将处于无效状态。
T*getPrevLink()该函数把迭代器“备份”到该列表中的前一链接。它把当前链接设置到该列表中的前一链接并且返回一个指向它的指针。但是,实际结果取决于在该函数被调用之前的检查元的状态。如果检查元处于有效状态并且没有到达该列表的前沿,则保持有效状态。如果检查元处于有效状态并且到达该列表的前沿,则它将转到无效状态,并且返回NULL指针。如果检查元处于无效状态,则它将保持在无效状态,并且返回NULL指针。SharedListNonatomicInspector<T>对象这是从SharedListInspector<T>402派生的一个具体类。它不提供除了基类提供的函数之外的其它函数。该类的对象具有该列表的非原子观察。该类的对象可以迭代正向通过该列表,但是自己不能改变它。SharedListMutator<T>对象该抽象类从SharedListIterator<T>401派生。它通过在列表中添加或删除链接,而增加改变列表的能力。它具有由从它派生的类所提供的列表的原子或非原子观察。
当调用一个改变函数(mutating function)时,一个客户变元可以处于任何状态。在该函数的实际执行中,变元通常必须(至少内部地)处于无效状态。为了使处于无效或过渡状态的变元“保持它在该列表中的位置”通过一个改变函数,该函数的完成必须能够恢复后来的状态。更一般地,所有改变函数包括表示当该功能完成时变元的当前链接(以及其状态)如何被处理的MutatorControl(变元控制)参数。下面的数值可能被指定conditionalUpdate=0该数字表示变元的当前链接不被改变,除非需要作出这种改变以完成该函数。如果当前链接被改变,则该变元将不“失去它在该列表中的位置”;新的当前链接将是现在跟随在旧的当前链接之前的链接之后的链接。如果它刚好是要被删除的链接,则原子变元的当前链接将仅仅被改变。非原子变元的当前链接被除了insertAfterCurrentLink()和removeAfterCurrentLink()函数之外的所有改变函数所改变。
unconditionalUpdate=1该数值表明如果该函数成功执行,变元的当前链接要被改变。如果插入一个链接,则新的当前链接将是新插入的链接。如果删除一个链接,则新的当前链接将是现在跟随在被删除链接之后的链接。
unconditionalReset=2该数值表示如果函数成功执行,则该变元被复位到无效状态。
各种插入和删除函数返回一个MutatorResult数值,其表示该函数成功或失败,以及当前链接是否被改变。如下数值可能被返回successfulAsRequested=0该数值表示所要求的函数成功执行,并且或者变元的当前链接没有改变,或者被无条件更新,或者该变元被无条件复位,如由MutatorControl数值所指定。
failedNoChange=1该数值表示所需函数失败,并且变元的当前链接没有被改变。这种情况也可以是用户错误的结果。
successfulWithChange=2该数值表示所需函数成功执行,但是变元的当前链接必须被改变。仅当conditionalUpdate被指定用于MutatorControl数值时,返回该数值。当在这种情况下,将对处于有效或过渡状态的非原子变元返回该数值,或者对删除刚好是当前链接的一个链接的一个原子变元返回。
failedWithChange=3该数字表示所需函数失败,并且变元的当前链接必须被改变以避免死锁。这仅仅对非原子变元出现,并且它的出现与指定的MutatorControl数值无关。但是,变元将不“失去它在该列表中的位置”。新的当前链接将使现在跟随在旧的当前链接之前的链接之后的链接。
客户可以把返回的MutatorResult与上述指定数值相比较,或者可以把它作为一个掩码并且测试其中的各个数位。各个数位的含义如下失败(failed)=0x0l如果函数失败,则该数位开启,如果成功则该数位关闭。
改变(changed)=0x02如果变元的当前链接被“意外”改变,则该数位开启。如果关闭,则表示该函数失败而没有改变变元的当前链接,或者函数成功,但是如果MutatorControl数值需要被无条件更新或复位,则仅仅改变该变元的当前链接。
SharedListMutator<T>类403提供如下函数。每个函数需要一个MutatorControl参数,并且返回或更新一个MutatorResult数值或参数。
T*removeFirstLink(MutatorControl,MutatorResult&)该方法从列表中删除第一链接,并且返回指向它的指针。如果在该列表中没有链接,则返回NULL。MutatorResult参数被更新以表示该函数是否成功及其对变元的当前链接的影响。参见表1,其用于描述可能返回各种MutatorResult数字的情况。
T*removeAfterArbitraryLink(T*refLink,MutatorControl,MutatorResult&)该方法从列表中删除跟随在特定的任意链接之后的链接,并且返回指向它的指针。如果特定的任意链接是该列表中的最后链接,则返回NULL。MutatorResult参数被更新以表示该函数是否成功及其对变元的当前链接的影响。参见表1,其描述可能返回各种MutatorResult数值的情况。
表1用于所选择删除函数的mutatorResult数值
0=条件更新 0=成功按照要求0=成功按照要求(conditional被删除的链接不 该变元保持在无效状态。update) 是当前链接。当前1=失败没有改变链接未改变。
(a)所引用的任意链接是1=失败没有改变 NULL,或者(b)该变元处于引用的任意链接 无效状态并且没有被删除是NULL或者没有 的链接。
被删除的链接。
2=成功并改变2=成功并改变 该变元处于有效或过渡状被删除的链接是 态。当前链接被改变为跟旧的当前链接。当 随在被删除的链接之后的前链接已经改变 链接。
为跟随在它之后 3=失败并改变的链接。
该变元处于有效或过渡状态,并且没有被删除的链接。该变元现在处于过渡状态。1=无条件更新0=成功按照要求0=成功按照要求(unconditional 当前链接现在是 当前链接现在是在被删除update) 跟随在被删除链 时跟随在被删除的链接之接之后的链接。 后的链接。
1=失败没有改变1=失败没有改变所引用的任意链 (a)所引用的任意链接是接是NULL或者没 NULL,或者(b)该变元处于有要删除的链接。
无效状态并且没有被删除的链接。
3=失败并改变该变元处于有效或过渡状态,并且没有被删除的链接。该变元现在处于过渡状态。2=无条件复位0=成功按照要求0=成功按照要求(unconditional 该变元被复位 该变元被复位到无效状reset) 到无效状态。
态。
1=失败没有改变1=失败没有改变所引用的任意(a)所引用的任意链接是链接是NULL NULL,或者(b)该变元或者没有被被处于无效状态并且没有删除的链接。被删除的链接。
3=失败并改变该变元处于有效或过渡状态,并且没有被删除的链接。该变元现在处于过渡状态。
该表格的原子变元部分还应用到removelLastLink()和removeBeforeArbitraryLink()函数。
MutatorResult removeArbitraryLink(T*oldLink,MutatorControl)该方法从该列表中删除指定的任意链接,并且返回表示该函数是否成功以及它对变元的当前链接的影响。参照表2,其描述可能返回的各种MutatorResult数值的情况。
表2用于removeArbitraryLink()函数的MutatorResult数值
0=条件 0=成功按照要求 0=成功按照要求更新 被删除的链接不是当该变元保持在无效状态。
前链接。当前链接未 1=失败没有改变改变。所引用任意链接是NULL1=失败没有改变 2=成功并改变引用的任意链接是 该变元处于有效或过渡状NULL。态。当前链接被改变为跟随2=成功并改变在被删除的链接之后的链被删除的链接是旧的接。
当前链接。当前链接已经改变为跟随在它之后的链接。1=无条 0=成功按照要求 0=成功按照要求件更新 当前链接现在是跟随在被删除时,当前链接现在在被删除链接之后的是跟随在被删除的链接之链接。后的链接。
1=失败没有改变 1=失败没有改变所引用的任意链接是所引用的任意链接是NULLNULL。2=无条 0=成功按照要求 0=成功按照要求件复位 该变元被复位到无效该变元被复位到无效状态。
状态。 1=失败没有改变1=失败没有改变 所引用的任意链接是NULL。
所引用的任意链接是NULLMutatorResult removeCurrentLink(MutatorControl)该方法尝试从列表中删除变元的当前链接。该函数可能成功或不成功。如果它不成功,这是因为另一个变元已经提交或者在该变元的当前链接之前插入一个链接,或者删除该变元的当前链接。无论该函数成功与否,该变元将具有新的当前链接。新的当前链接将是现在跟随在进行删除时的当前链接之前的链接之后的链接。按照这种方式,变元不会“失实施例5(R)-1-[2-(2,4-二氯苯基)-2-(丙烯氧基)乙基]-1H-咪唑(烯菌灵)的效果对构巢曲霉的杀菌活性根据标准稀释方法制备外消旋和单一对映异构体的烯菌灵丙酮溶液。每一溶液以5微升(μl)等份点在预先用构巢曲霉接种物处理的10cm马铃薯葡萄糖琼脂板的中心。在未处理板(对照)上,接种物在3天内长成菌落。引入计算杀菌剂的抑菌率,观察抑菌圈,根据使用的杀菌化合物(即外消旋物或单一对映异构体)的浓度和同一性产生不同大小的抑菌圈。结果列于表1中。
表1
根据上述的抑菌圈大小,(S)对映异构体在给定浓度下效果是同样浓度的(R)-对映异构体的10倍。
该变元不在有效状该变元不在有效状态。
态。 3=失败并改变当前链接现在是跟随在尝试删除时的当前链接之前的链接之后的链接。2=无条 0=成功按照要求 0=成功按照要求件复位 该变元被复位到无该变元被复位到无效状态。
效状态。 1=失败没有改变1=失败没有改变该变元不在无效状态。
该变元不在有效状 3=失败并改变态 当前链接是现在跟随在尝试删除时的当前链接之前的链接之后的链接。
T*removeAfterCurrentLink(MutatorControl,MutatorResult&)该函数尝试删除紧接着在当前链接之后的链接,并且返回一个指向它的指针。如果当前链接是该列表中的最后链接,则返回NULL。该函数可能成功或不成功。如果它不成功,这是由于另一个变元提交删除该变元的当前链接。在这种情况下,该变元将具有新的当前链接,这是一个现在跟随在进行删除时的旧当前链接之前的链接之后的链接。按照这种方式,该变元不会“失去它在列表中的位置”。MutatorResult被更新以表示该函数成功与否以及它对变元的当前链接的影响。参见表4,其中描述可能返回各种MutatorResult数值的情况。
表4用于removeAfeterCurrentLink()函数的MutatorResult数值
0=条件 0=成功按照要求0=成功按照要求更新当前链接未改变。
当前链接未改变。
1=失败没有改变1=失败没有改变当前链接是最后链 当前链接是最后链接,或者接,或者变元处于 变元不处于有效状态。
无效状态。
3=失败并改变当前链接现在是跟随在尝试删除时的旧当前链接之前的链接之后的链接。1=无条 0=成功按照要求 0=成功按照要求件更新 当前链接现在是跟当前链接是跟随在被删除随在被删除链接之链接之后的链接。
后的链接。
1=失败没有改变1=失败没有改变当前链接是最后链接,或者当前链接是最后链变元不处于有效状态。
接,或者变元处于 3=失败并改变无效状态。
新的当前链接现在是跟随在尝试删除时的旧当前链接之前的链接之后的链接。2=无条 0=成功按照要求 0=成功按照要求件复位该变元被复位到无 该变元被复位到无效状态。
效状态。
1=失败没有改变1=失败没有改变 当前链接是最后链接,或者当前链接是最后链 变元不处于有效状态。
接,或者变元处于 3=失败并改变无效状态。新的当前链接是现在跟随在尝试删除时的当前链接之前的链接之后的链接。MutatorResult insertFirst(T*newLink,MutatorControl)该函数在列表的前方插入特定链接,并且返回表示这对变元的当前链接的影响的一个结果。参见表5,其中描述可能返回各种MutatorResult数值的情况。
MutatorResult insertLast(T*newLink,MutatorControl)该函数在列表的末尾插入特定链接,并且返回表示这对变元的当前链接的影响的一个结果。参见表5,其中描述可能返回各种MutatorResult数值的情况。
MutatorResult insertBeforeArbitraryLink(T*newLink,T*refLink,MutatorControl)该方法紧接着在特定引用链接之前插入特定链接,并且返回表示这对变元的当前链接的影响的一个结果。参见表5,其中描述可能返回各种MutatorResult数值的情况。
MutatorResult insertAfterArbitraryLink(T*newLink,T*refLinkMutatorControl)该方法在特定引用链接之后插入特定链接,并且返回表示这对变元的当前链接的影响的一个结果。参见表5,其中描述可能返回各种MutatorResult数值的情况。
表5用于选择插入函数的MutatorResult数值
0=条件 0=成功按照要求0=成功按照要求更新当前链接未改变。
该变元处于并且保留在无效1=失败没有改变 状态。
要被插入的链接 1=失败没有改变或者引用的任意 要被插入的链接或者所引用链接是NULL。
的任意链接是NULL。
2=成功并改变该变元处于有效或过渡状态。
新插入的链接现在是当前链接。1=无条 0=成功按照要求0=成功按照要求件更新 新插入的链接现 新插入的链接现在是当前链在是当前链接。 接。
1=失败没有改变1=失败没有改变链接被插入或者 要被插入的链接或者所引用所引用的任意链 的任意链接是NULL。
接是NULL。2=无条 0=成功按照要求0=成功按照要求件复位 该变元被复位到 该变元被复位到无效状态。
无效状态。
1=失败没有改变1=失败没有改变 要被插入的链接或者所引用要被插入的链接 的任意链接是NULL。
或者所引用的任意链接是NULL。
MutatorResult insertBeforeCurrentLink(T*newLink,MutatorControl)该方法尝试紧接着在变元的当前链接之前插入特定链接。它可能成功或不成功。如果它不成功,这是由于另一个变元要在该变元的当前链接之前插入一个链接,或者要删除该变元的当前链接。无论该函数成功与否,该变元将具有一个新的当前链接。该新的当前链接是跟随在进行插入时的旧当前链接之前的链接之后的链接。按照这种方式,该变元不会“失去它在列表中的位置”。该返回值表示该函数成功与否以及它对变元的当前链接的影响。参见表6,其中描述可能返回各种MutatorResult数值的情况。
表6用于insertBeforeCurrentLink()函数的MutatorResult数值
0=条件 0=成功按照要求 0=成功按照要求更新当前链接未改变。当前链接未改变。
1=失败没有改变 1=失败没有改变要被插入的链接 要被插入的链接是NULL,或是NULL,或该变 该变元处于无效状态。
元处于无效状态。 3=失败并改变新的当前链接现在是跟随在尝试插入时的旧当前链接之前的链接之后的链接。1=无条 0=成功按照要求 0=成功按照要求件更新 新插入的链接现 新插入的链接现在是当前链在是当前链接。
接。
1=失败没有改变 1=失败没有改变要被插入的链接 要被插入的链接是NULL,或是NULL,或者该 者该变元处于无效状态。
变元处于无效状3=失败并改变态。
新的当前链接现在是跟随在尝试插入时的旧当前链接之前的链接之后的链接。2=无条 0=成功按照要求0=成功按照要求件复位 该变元被复位到 该变元被复位到无效状态。
无效状态。
1=失败没有改变1=失败没有改变 要被插入的链接是NULL,或要被删除的链接 者该变元处于无效状态。
是NULL,或者该 3=失败并改变变元处于无效状 新的当前链接是现在跟随在态。
尝试插入时的旧当前链接之前的链接之后的链接。
MutatorResult insertAfterCurrentLink(T*newLink,MutatorControl)该方法尝试紧接着在当前链接之后插入特定的链接。该函数可能成功或不成功。如果它不成功,这是由于另一个变元已经要删除该变元的当前链接。在这种情况下,该变元将具有新的当前链接,这是一个现在跟随在进行插入时的旧当前链接之前的链接之后的链接。按照这种方式,该变元不会“失去它在列表中的位置”。返回数值表示该函数成功与否以及它对变元的当前链接的影响。参见表7,其中描述可能返回各种MutatorResult数值的情况。
表7用于insertAfterCurrentLink()函数的MutatorResult数值
0=条件 0=成功按照要求0=成功按照要求更新当前链接未改变。
当前链接未改变。
1=失败没有改变1=失败没有改变要被插入的链接是 要被插入的链接是NULL,NULL,或该变元处 或该变元不是处于有效状于无效状态。
态。
3=失败并改变新的当前链接现在是跟随在尝试插入时的旧当前链接之前的链接之后的链接。1=无条 0=成功按照要求0=成功按照要求件更新 新插入的链接现在 新插入的链接现在是当前是当前链接。
链接。
1=失败没有改变1=失败没有改变要被插入的链接是 要被插入的链接是NULL,NULL,或者该变元 或者该变元不处于有效状处于无效状态。 态。
3=失败并改变新的当前链接现在是跟随在尝试插入时的旧当前链接之前的链接之后的链接。2=无条 0=成功按照要求0=成功按照要求件复位 该变元被复位到无 该变元被复位到无效状态。
效状态。1=失败没有改变1=失败没有改变 要被插入的链接是NULL,要被删除的链接是 或者该变元不处于有效状NULL,或者该变元 态。
处于无效状态。
3=失败并改变新的当前链接是现在跟随在尝试插入时的旧当前链接之前的链接之后的链接。SharedListAtomicMutator<T>对象这是一个从SharedListMutator<T>403派生的具体类。该类的对象具有该列表的原子观察,这意味着它们可以保证没有其它变元处理该列表。该类的对象可以迭代正向或反向地通过该列表,并且可以从该列表中插入或删除链接。
由于该原子观察,使得该类还提供如下函数T*getLastLink()该函数返回一个指向该列表中的最后链接的指针。在该函数被调用之后,该变元将处于有效状态,除非在该列表中没有链接。在这种情况下,将返回NULL指针,并且该变元将处于过渡状态。
T*getPrevLink()该函数把变元“备份”到该列表中的以前链接。它把其当前链接设置到该列表中的以前链接并且返回一个指向它的指针。但是,实际结果取决于在该函数被调用之前的变元的状态。如果该变元处于有效状态,并且没有到达该列表的前沿,则它将保持在有效状态。如果该变元处于过渡状态并且没有到达该列表的前沿,则它将转到有效状态。如果该变元处于有效或过渡状态并且到达该列表的前沿,则它将转到无效状态,并且将返回NULL指针。如果该变元处于无效状态,则它将保持在无效状态,并且返回NULL指针。
T*removeLastLink(MutatorControl,MutatorResult&)该方法从列表中删除最后链接,并且返回一个指向它的指针。如果在该列表中没有链接,则返回NULL。MutatorResult参数被更新以表示该函数成功与否以及它对变元的当前链接的影响。参见表1,其中描述可能返回各种MutatorResult数值的情况。
T*removeBeforeArbitraryLink(T*refLink,MutatorControl,MutatorResult&)该方法从列表中删除紧接着在特定的任意链接之前的链接,并且返回一个指向它的指针。如果特定的任意链接是在该列表中的第一链接,则返回NULL。MutatorResult参数被更新以表示该函数成功与否以及它对变元的当前链接的影响。参见表1,其中描述可能返回各种MutatorResult数值的情况。SharedListNonatomicMutator<T>对象这是一个从SharedListMutator<T>403派生的具体类。该类的对象可以正向迭代通过该列表,并且可以从该列表中插入或删除链接,而相同类的其它对象也可以改变该列表。SharedListIterator<T>同时访问的概述表8中根据类型概述了可能在两个迭代器尝试同时访问SharedList<T>对象而在它们之间出现的冲突。如果两个迭代器具有列表级冲突,则它们不能同时访问该列表。(其在该列表上的锁定被限于它的存在的迭代器将在它构造过程中等待解决冲突访问。锁定是动态的不限于其存在的迭代器将在从无效状态转移或者开始改变函数的状态点处等待,并且当它处理无效状态或不执行改变函数的任何时候释放其锁定)。如果两个迭代器具有链接级冲突,则它们可以同时访问该列表,但是当引用相同的链接指针时必须轮流进行。
表8用于SharedListIterator<T>对象的访问冲突的概括
*非原子检查元不必在链接级冲突中等待变元。但是该变元必须等待非原子检查元来从冲突链接中移开。客户责任使用SharedList<T>对象的客户被期望遵守特定的规则以避免不适当的引用等等。即,客户应当使用特定的接口,而不是尝试直接操纵指针。另外,当调用与SharedList<T>对象相关的函数时,客户适当确认特定参数的正确性,例如,用户不适当尝试把一个已经在列表中的链接插入到该列表中。在此没有包含这种可能项目的穷举列表。
其中一个更加重要的客户责任是保证当调用例如insertBeforeArbitraryLink()、removeArbitraryLink()等等函数时对经过的任意链接的任何引用实际上都是对该列表中的链接的引用,并且将实际上在操作过程中保留在链接的列表中(除非如在此所述被一个变元所删除)。
客户可以选择从SharedList<T>和适当的迭代器中派生他们的类,或者把这些类与他们自己的类打包在一起。打包可以用于在变元函数中隐藏MutatorControl参数,并且隐藏任何不适当被暴露的函数(可能是引用任意链接的函数)。
链接表的结构内部操作介绍SharedChain和SharedChainIterator对象到目前为止所述的SharedList<T>和SharedListIterator<T>对象向客户提供接口,但是它们仅仅包住完成所有工作的实际对象。包装类(wrapper classe)通过在T*和指向链接的指针的内部表示之间投影(casting)而提供模板化。所有函数被内联(inline)并且在内部(inner)对象中简单地称为外联函数(outline function),从而在不同客户对象上的模板化不会略微增加代码长度。
内部对象在本申请说明书的剩余部分中描述。它们排列在与包装对象相同的层级上,并且支持相同的接口函数,加上多个附加内部函数。包装类的函数的实现仅仅是调用内部类上的相应函数。
图5示出各种外部和内部类之间的关系以及它们的继承层级。做出如下规定。名称相类似在包装类名中的术语“列表(List)”由内部类中的术语“链(Chain)”所代替,并且取消模板化。迭代器类的层级相同,只是名称会改变。SharedChainIterator基类具有指向它所属的SharedChain对象的指针。帮助对象除了SharedChain和SharedChainlterator对象之外,还有一些在下文列出的用于实现中的内部对象。SharedChainBlocker对象SharedChainBlocker对象(也简称为″阻挡元对象″)被变元用于执行链接的阻挡和解阻挡(unblock),和需要的和其它非原子迭代器(检查元和变元)的同步。SharedChain对象保持一组阻挡元对象,并且在改变函数的过程中把它们与一个变元相关的。阻挡元对象以及链接指针的阻挡和解阻挡(unblocking)在下文中更加具体描述。
SharedChainView对象SharedChainView类是一个抽象基类。从该类派生出来的对象由迭代器用于执行实际迭代功能,和与(其它)变元同步。在此由两种由该基类派生的观察对象SharedChainAtomicView和SharedChainNonatomicView。
SharedChainAtomicView这种对象被在一个原子迭代器(检查元或变元)中构成。得知没有(其它)变元可以插入或删除链接,它知道如何处理该链中的链接。SharedChainAtomicView对象相当简单并且基本上包含指向迭代器的当前链接的指针。
SharedChainNonatomicView这种对象(也简称为“观察对象”)被非原子检查元和非原子变元所使用。得知(其它)变元还可能插入或删除链接,它知道如何处理链中的链接。SharedChain对象保持两组SharedChainNonatomicView对象,一个由非原子检查元所使用,并且另一个由非原子变元所使用。它把其中一个观察对象与非原子迭代器(检查元或变元)相关联,在该迭代器处于有效或过渡状态的时候。非原子观察对象在下文中更加具体描述。
没有在此描述其它可以用于支持附加的次要功能,用于代码调试、用于系统性能分析、或者用于其它目的的帮助对象。操作概述SharedChain对象保持指向在链中的第一链接的指针,以及指向链中的最后链接的指针。相邻的链接在正向和反向方向上相互指向。在最后链接中的正向指针以及在第一链接中的反向指针为NULL。图6示出具有3个链接的示例SharedChain对象601的简化示图。
由于原子检查元可以保证没有变元对链接列表进行操作,它们自由地在正向和反向方向上跟随链接指针。它们被分解为更加锁碎,剩下原子变元、非原子变元和非原子检查元,这在下文中更加具体描述。
在下文的描述中,原子变元被更具体地描述。但是应当知道,由于向后兼容性的原因、支持可能专业化的操作系统功能以及类似原因,原子变元(以及原子检查元)被提供在优选实施例中。本发明的要点是尽可能避免使用列表级锁定机制,并且支持原子变元对于实现本发明不是必须的。非原子迭代器(nonatomic iterator)非原子检查元仅仅遍历该链。由于它们具有该链的非原子观察,因此当它们前进时,无论它们是否看见任何被插入或删除的特定链接都无所谓。唯一重要的是它们可以安全地从一个链接前进到下一个链接,并且当特定链接是它们的当前链接时,该链接不能被从链中删除。
非原子变元也可以遍历该链,并且类似于非原子检查元,它们必须安全地从一个链接前进到下一个链接,并且保证当前链接不能被从链中删除。由于它们可以根据它们的当前链接插入或删除链接(例如,可能该链保持一些优先级),还重要的是前一链接不能被删除,并且没有其它链接可以插入到当前链接和前一链接之间。变元(mutator)为了插入一个链接,一个变元需要分别初始化在新的链接中引用下一链接和前一链接的正向和反向指针,并且改变在前一链接中的正向指针以及在下一链接的反向指针,以引用新的链接。为了删除一个链接,变元需要改变在前一链接中的正向指针以引用下一链接,并且改变在下一链接中的反向指针以引用前一链接。
由于多个更新不能原子地完成,它们通过首先按很好定义的顺序阻挡所有受影响链接指针而一次一个地完成(阻挡在下文中更加具体描述)。阻挡一个链接指针的变元已经保留改变它的权利。一个链接指针已经被阻挡的事实防止其它变元阻挡它或遍历它。由于一个变元已经阻挡所有受影响的链接指针,然后它通过用它们所需的新数值(这也按很好定义的顺序)来代替该指针从而解阻挡它们,从而插入或删除所需链接。迭代器和变元之间的相互作用为了插入或删除一个链接,迭代器首先阻挡所有受影响的链接指针。一个非原子检查元不受被阻挡的链接指针所影响。它可以前进通过受阻挡的链接指针并且把该链中的下一链接确立为它的(新)当前链接。迭代(非原子)变元被受阻挡链接指针所阻止。当它前进并遇到一个受阻挡链接指针时,它必须等待该链接指针被解阻挡。另一个变元在尝试阻挡一个已经被阻挡的链接指针时将失败。它可以选择等待该链接指针被解阻挡,并且当它被解阻挡时,该变元必须尝试再次阻挡该链接指针。
一旦一个变元已经阻挡插入或删除链接所需的所有链接指针,它必须等待所有(非原子)检查元以及迭代(非原子)变元,这取决于任何受阻挡链接指针,以前进通过它们。阻挡变元向每个这种迭代器表示该迭代器必须在它已经前进通过受影响的链接的指针时通知该变元,然后等待所有这种通知出现。
最后,一旦变元肯定没有依赖于受阻挡链接指针的迭代器,则它解阻挡它们,从而插入或删除所需链接。一旦一个链接指针被解阻挡,它可以由其它迭代器所遍历,或者由另一个变元所阻挡,而不知道它已经最近被解阻挡。同时,如果在此有等待链接指针被解阻挡的其它变元,则被解阻挡变元唤醒它们。作为唤醒的结果,在受阻挡正向链连指针上等待的所有迭代变元将原子地完成它们的前进过程,并且将把解阻挡的正向指针现在指向的链接确立为它们的新当前链接。在受阻挡链接指针上等待的所有阻挡变元将重新尝试阻挡现在已经被解阻挡的链接指针。迭代当非原子迭代器(检查元或变元)处于有效或过渡状态时,具有与它相关的SharedChainNonatomic观察对象。是该观察对象给予迭代器迭代通过该链并且保持跟踪当前链接的能力。SharedChain对象保持这些观察对象的两个列表。一个列表由非原子检查元所使用,另一个由非原子变元所使用。当非原子迭代器从无效状态转移时,可用观察对象在适当列表中找到并且被分配给它。如果所有观察对象在该列表中为占用状态,则新的一个被产生并且添加到列表。当迭代器被复位到无效状态,则观察对象被用于由另一个(相同类型)的非原子迭代器重新使用。
SharedChainNonatomicView对象包含识别迭代器的当前链接的信息。由于所有观察对象存在于两个列表中的一个列表中,当变元插入后删除链接时,它们可以查找所有观察对象,并且确定哪一个依靠于被改变的链接指针,并且可以适当地与它们相互作用。
一个迭代器通过一个有点类似于数学归纳法的过程,遍历在该链中的指针需要一种方式从无效状态转移到第一链接(或者在任意链接之后的链接),以及用一种方式从任意链接前进到下一链接。迭代器的SharedChainNonatomicView对象具有两个字段以保持跟踪其当前链接curLink 706包含迭代器的当前链接的地址。当该字段指向一个链接时,该链接不能被从该链中删除。
curPtr 705包含在一个链接中的正向指针的地址。当一个迭代器具有当前链接时,该字段指向的正向指针取决于该迭代器是否为一个检查元或变元。对于一个检查元,该字段指向当前链接中的正向指针。对于一个变元,该字段指向在前一链接中的正向指针(其中,除非被阻挡,否则将指向当前链接)。这还防止前一链接被从该链中删除,并且防止另一个链接被插入在前一链接和当前链接之间。
图7示出用于一个迭代非原子变元的观察对象701以及用于非原子检查元702的观察对象702。非原子变元把“链接B”看作为它的当前链接,因为这在它的观察对象中curLink指向“链接B”并且curPtr指向在“链接A”中的正向指针。非原子检查元把“链接C”当作它的当前链接,因为这在它的观察对象中,curLink指向“链接C”并且curPtr指向“链接C”中的正向指针。开始一个迭代器-得到一个指向第一链接的指针下文描述当开始一个迭代器时更新curLink 706和curPtr 705的过程。在该描述中,对阻挡元交互给予较少的考虑,因为这在下文中更加具体描述。
1.当getFirstLink()函数被调用以把迭代器转到有效状态时,一个观察对象被分配给该迭代器。
2.curPtr 705被设置,使得它指向在SharedChain对象中的第一链接指针(first_link-pointer)字段602。
3.使用在后面更加具体描述的算法,curPtr 705被解除引用(de-reference),以给出指向第一链接的指针,并且它的地址被保存在curLink 706中。在该列表中的第一链接现在变为迭代器的当前链接。参见图7,curPtr将指向SharedChain对象601内的第一链接指针字段602,并且curLink将指向“链接A”。在这一点上,“链接A”不在被从链中删除,并且没有链接可以插入在它的前方。
4.如果迭代器是一个变元,则这是该过程停止之处。如果迭代器是一个检查元,则curPtr 705被设置,使得它指向当前链接中的正向指针。再次参见图7,这仍然防止“链接A”被从链中删除,但是现在允许其它链接插入在其前方。前进一个迭代器-得到一个指向下一个链接的指针当前进时,检查元和变元使用相同的步骤来设置curLink 706和curPtr 705,但是它们以相反的次序来完成该操作。
1.当getNextLink()函数被调用时,如果迭代器是一个检查元,则跳到步骤2。如果是一个变元,则完成在上述步骤4中相同处理,对检查元给出一个指向第一链接的指针设置curPtr 705,使得它指向当前链接中的正向链接指针。参见图7,CurPtr 705将指向“链接A”中的正向指针,并且curLink 706将指向“链接A”。这仍然防止当前链接(“链接A”)被从链中删除,但是前一链接不再被保护,并其它链接现在可以紧接着插入在当前链接之前。
2.使用在下文中更加具体描述的算法,curPtr 705被解除引用以把一个指针给予下一个链接,并且该地址被存储在curLink 706中。这现在变为迭代器的新当前链接。参见图7,curPtr将指向“链接A”中的正向指针,并且curLink将指向“链接B”。在这一点,“链接A”和“链接B”都不能被从链中删除,并且链接也不能插入在它们之间。
3.如果迭代器是一个变元,则这是该过程停止之处。如果迭代器是一个检查元,则curPtr 705被设置,使得它指向当前链接中的正向链接指针。再次参见图7,这仍然防止“链接B”被从链中删除,但是不保护“链接A”,并且允许其它链接插入在它们之间。前进到链(chain)的末尾最后当迭代器前进到链的末尾时,NULL被返回用于当前链接。如果迭代器是一个检查元,则它被复位到无效状态。这使得它的观察对象被复位,使得它没有当前链接,并且与迭代器相分离以及可以由另一个非原子检查元重新使用。
但是,如果迭代器是一个变元,它现在处于过渡状态,并且观察对象必须保留,curPtr 705指向最后链接中的正向指针,并且curLink706包含NULL。在该状态下,在链中的最后链接不能被删除,并且另一个链接不能插入在它之后。但是,insertBeforeCurrentLink()函数可以在该变元上被调用,并且它将把新链接添加到链的末尾。否则,reset()函数可以被在变元上调用,以把它转到无效状态。复位该变元使得它的观察对象被复位,从而它没有当前链接,并且与变元相分离以及可由另一个非原子变元重新使用。与阻挡变元交互作用有两个前进的迭代器可以与阻挡变元交互作用的点。当迭代器改变在它的观察对象中的curPtr 705字段时,这是当它被认为已经前进到下一个链接的时候。当改变curPtr时一个前进迭代器通知是否一个阻挡变元正在等待它,来在其前进时被告知当一个迭代器解除引用在它的观察对象中的(新)curPtr字段时,它可以发现该链接指针被阻挡。检查元将能够前进通过一个阻挡的链接指针,但是一个变元必须等待该链接指针被解阻挡。阻挡链接指针图8示出SharedChain对象、阻挡元对象和链接之间的关系。当一个变元(原子或非原子)插入或删除一个链接时,它具有与其相关的SharedChainBlocker对象801。是阻挡元对象给予变元阻挡和解阻挡链接指针和与其它变元或迭代器(必要时等待并相互唤醒)互动的能力。SharedChain对象601保持一个阻挡元对象的列表,并且包含指向该列表中的第一阻挡元对象的指针803。当变元开始一个改变函数时,一个可用的阻挡元对象被在该列表中查找并分配给该它。如果列表中所有阻挡元对象都忙,再创建一个新的阻挡对象并加入该列表。当改变函数完成并且没有对阻挡元对象的更突出的引用时,它可以由另一个改变函数重新使用。
变元阻挡一个链接指针,以获得该链接指针的专用权。它通过改变该指针使得它不再指向相邻的链接而指向变元的阻挡元对象从而阻挡该链接指针,同时原子地提取链接指针的原始内容。当阻挡一个正向链接指针时,它的原始内容还自动存储在阻挡元对象中(在下一个链接next link字段302),从而非原子检查元可以遍历通过一个被阻挡链接指针。
改变链接指针对所有其它引用该指针的迭代器有影响,并且有一种是仅仅通过查看它而确定该链接指针是否指向相邻链接或者指向阻挡元对象的方法。在优选实施例的情况中,链接和阻挡元对象必须驻留在至少一个M字节(M-byte)边界上,使得它们地址的低N位总是为0。在该优选实施例中,M为16,并且N为4。因此,在正向和反向链接指针中的这些数位可以被用作标志。下文中有更具体的描述,但是到目前为止足以说明当这些位为关闭(off)时,链接指针指向相邻链接,并且当变元把它的阻挡元对象的地址存储在链接指针中时,它总是使低(x01)位开启(on)。该数位表示链接指针被阻挡并且(通过屏蔽低4位),指向阻挡元对象。
图8示出阻挡元对象801,其阻挡了在“链接A”中的正向链接指针805。遇到被阻挡链接指针的其它迭代变元和阻挡变元将必须等待它被解阻挡。遇到阻挡链接指针的检查元可以从阻挡元对象(通过下一个链接字段802)获得指向“链接B”的指针,并且不必须等待该链接指针被解阻挡。原子变元这一部分描述涉及原子变元的多个改变函数中的处理。由于链的变元的原子视图,从而可以自由地跟随在链中的正向和反向指针,并且有助于简化该处理。但是,它提供一种良好的定向方法,当以后考虑非原子变元时这可能是有用的。参照前图,这有助于跟踪各种链接指针。插入一个链接,原子方法在此有可以把一个新链接插入到链中的各种函数。所有这些函数可以被认为是定位前一链接的简单的前端,然后执行在插入一个链接,普通原子过程中所述的步骤。
insertAfterArbitraryLink()该方法紧接着在特定的任意链接(其假设为在该链中)之后插入一个新的链接。执行插入一个链接,普通原子过程的步骤,把一个引用传送到作为前一链接的任意链接。
insertAfterCurrentLink()该方法紧接着在变元的当前链接之后插入一个新链接。如果该变元没有当前链接,则该方法失败。否则,执行插入一个链接,普通原子过程的步骤,把一个引用传送到作为前一链接的当前链接。
insertFirst()该方法在链中插入一个新链接作为第一链接。执行插入一个链接,普通原子过程的步骤,把NULL作为一个引用传送到前一链接。
insertBeforeArbitraryLink()该方法紧接着在特定的任意链接(该链接假设在该链中)之前插入一个新的链接。它跟随着在任意链接中的反向指针来定位前一链接。执行插入一个链接,普通原子过程的步骤,把一个引用传送到前一链接。
insertBeforeCurrentLink()该方法紧接着在变元的当前链接之前插入一个新的链接。如果该变元没有当前链接,则该方法失败。否则,在当前链接中的反向指针被跟随,以定位前一链接,并且执行插入一个链接,普通原子过程的步骤,把一个引用传送到前一链接。
insertLast()该方法在该链中插入一个新的链接作为最后链接。它从在SharedChain对象中的最后链接指针字段603获得指向当前最后的链接的一个指针。执行插入一个链接,普通原子过程的步骤,把一个引用传送到作为前一链接的最后链接。插入一个链接,普通原子过程该过程完成紧接着在前一链接之后插入一个新的链接。对前一链接的引用被作为一个输入参数而传送。
1.在该链中的链接的计数值被增加。
2.在前一链接中的正向指针被定位。但是,如果前一指针为NULL,则意味着新的链接将被作为第一链接插入在该链中。在这种情况下,该函数定位在SharedChain对象中的第一链接指针字段602。
3.定位于步骤2的指针跟随到下一个链接。
4.在下一链接中的反向指针被定位。但是,如果下一链接是NULL,这意味着新的链接将作为该链中的最后链接而插入。在这种情况下,该函数定位在SharedChain对象中的最后链接指针字段6035.新的链接的正向指针被初始化为指向下一链接,并且其反向指针指向前一链接。如果该链接定义了一个指向链对象的字段,则该字段也被初始化。
6.在前一链接内的正向指针(定位于步骤2)被阻挡。这还自动地把指向下一链接的指针存储到阻挡元对象内的下一链接字段802中。(这允许任何非原子检查元前进通过指向下一链接的被阻挡链接指针。)7.在阻挡元对象中的下一链接字段被改变为指向新的链接。这将保证从现在开始,前进通过被阻挡链接指针的任何非原子检查元将看到新插入的链接。
8.该方法等待在前进通过受阻挡链接指针到达下一链接(不是新链接)的过程中的任何非原子检查元,以完成它们的前进过程。
9.在下一链接中的反向指针(定位于步骤4)被改变为指向新的链接。
10.在前一链接中的正向指针(阻挡于步骤6)被改变为指向新的链接。删除一个链接,原子方法有多种函数(方法)可以从链中删除一个链接。它们都可以被认为是定位前一链接的简单的前端,然后紧接着执行在删除一个链接,普通原子过程中所述的步骤。
removeArbitraryLink()该方法删除一个特定的任意链接(其假设为在该链中)。它跟随着在任意链接中的反向指针,以定位前一链接。然后执行删除一个链接,普通原子过程中的步骤,传递一个到前一链接的引用。
removeLastLink()该方法从链中删除最后链接。如果在SharedChain对象中的最后链接指针(last_link_pointer)字段603为NULL,则没有要被删除的链接。否则它将跟随着最后链接指针字段603在该链中定位最后链接,并且跟随着其中的反向指针定位前一链接。然后执行删除一个链接,普通原子过程中的步骤,传送一个到前一链接的引用。
removeFirstLink()该方法从链中删除第一链接。然后执行删除一个链接,普通原子过程中的步骤,传送NULL作为一个到前一链接的引用。
removeBeforeArbitraryLink()该方法删除紧接着在任意链接(假设在该链中)之前的链接。如果在任意链接中的反向指针为NULL,则没有链接被删除。否则,它将跟随着在任意链接中的反向指针定位要被删除的链接,并且跟随着在其中的反向指针定位前一链接。然后执行删除一个链接,普通原子过程中的步骤,传递一个到前一链接的引用。
removeAfterArbitraryLink()该方法删除紧接着在特定的任意链接(假设在该链中)之后的链接。然后执行删除一个链接,普通原子过程中的步骤,把一个引用传送到作为前一链接的任意链接。
removeCurrentLink()本方法删除变元的当前链接。如果该变元没有当前链接,则在此没有要删除的链接。否则,跟随着在当前链接中的反向指针定位前一链接。然后执行删除一个链接,普通原子过程中的步骤,把一个引用传送到前一链接。
removeAfterCurrentLink()该方法删除跟随在变元的当前链接之后的链接。然后执行删除一个链接,普通原子过程中的步骤,把一个引用传送到作为前一链接的当前链接。删除一个链接,普通原子过程执行下文所述的步骤以完成一个链接的删除。对前一链接的引用被作为输入参数而传送。要被删除的链接是紧接着在前一链接之后的链接。
1.在前一链接中的正向指针被定位。但是,如果前一链接为NULL,则被删除链接是在该链中的第一链接。在这种情况下,该函数定位在SharedChain对象中的第一链接指针字段602。
2.如果在步骤1中定位的链接指针是NULL,则没有被删除的链接。否则该方法阻挡该链接指针并且继续如下步骤。(阻挡该链接指针原子地把指向被删除的链接的指针存储到阻挡元对象中的下一链接字段802。这使得遇到在前一链接中的受阻挡正向链接指针的任何非原子检查元通过受阻挡链接指针,并且查找还没有被删除的链接。)3.使用在步骤2中阻挡的链接指针的旧数值定位要被删除的链接。
4.该方法阻挡在要被删除的链接中的正向指针。并且还原子地把指向下一链接的指针存储到阻挡元对象中的下一链接字段802中。从这一点开始,遇到在前一链接或被删除链接中的受阻挡的正向指针的任何非原子检查元将不再看到被删除的链接,而是跳过它,看到下一个链接。
5.该方法等待任何(非原子)检查元,该检查元仍然前进到被删除的链接或者当前链接是要被删除的链接,以通过该链接。
6.下一链接从在步骤4中阻挡的链接指针的旧数值定位。
7.该方法定位在下一链接中的反向指针。但是,如果下一链接为NULL,则被删除的链接是该链中的最后链接。在这种情况下,它在SharedChain对象中定位最后链接指针字段603。
8.在步骤7中定位的反向指针被改变为指向前一链接。
9.在步骤2中阻挡的在前一链接中的正向指针被改变为指向下一链接。
10.在链中的链接计数值被减小。
11.在被删除链接中的正向和反向链接指针字段(以及可选链指针字段,如果它被定义了)被设置为NULL。对原子变元的当前链接的考虑当开始执行改变函数时,一个变元可能具有或没有当前链接。如果一个原子变元具有当前链接,则它可能保持当前链解阻挡过它所执行的任何插入或删除函数,除非它删除的链接刚好是其当前链接。在这种情况下,变元必须被复位,或者一个新的当前链接必须被选择。当执行一个改变函数时,把一个当前链接分配到一个变元,或者改变变元的当前链接也是合理的。在任何一种情况中,由于该变元具有原子观察,因此这些考虑不是特别重要。但是对于非原子变元来说以及为了与它们兼容,这些考虑是更加重要的,原子变元函数取一个输入MutatorControl参数,并且返回(或者更新)MutatorResult,并且支持属于当前链接的所有选项。非原子变元该部分描述涉及非原子变元的各种改变函数中的处理。变元的非原子观察使得跟随和阻挡链接指针变得更加复杂,因为其它非原子变元也可能正在尝试阻挡它们。必须采取特别的考虑来避免死锁。链接指针必须以很好定义的顺序阻挡和解阻挡。在一些情况中,需要延缓尝试性的受阻链接指针,暂时延迟另一个变元。有两个例外(insertAfterCurrentLink()和removeAfterCurrentLink()),一个变元不能在执行改变函数时保持当前链接。但是,一个新的当前链接(其保留在链中的变元位置)可以在改变函数完成时被分配到该变元。插入一个链接,非原子方法为了把一个链接插入到链中,有两个必须首先被阻挡的链接指针在前一链接中的正向指针,以及在下一链接中的反向指针。在前一链接中的正向指针的阻挡是一个关键阻挡。一旦该链接指针被阻挡,则它确定新链接被插入的位置。
图9示出用于一个变元的阻挡元对象,其已经阻挡把“链接B”插入到链中的“链接A”和“链接C”之间所需的链接指针。被阻挡的链接指针(即,在“链接A”中的正向链接指针901以及在“链接C”中的反向链接指针902)都指向阻挡元对象,并且x01位被设置为开启。在阻挡元对象中的下一链接字段802指向“链接B”,使得遇到“链接A”中的受阻挡正向指针的非原子检查元将看到作为下一链接的“链接B”有各种把链接插入到链中的方法。所有这些方法可以被认为是前端而开始,然后进行到要继续的另一个方法。
insertFirst()该方法定位在SharedChain对象中的第一链接指针字段602。这是必须被首先阻挡的链接指针,并且将最后指向新插入的链接,该链接将是在该链中的第一链接。执行插入一个链接,普通非原子过程中的步骤,把传送一个到在SharedChain对象中的第一链接指针字段602的引用。
insertAfterArbitraryLink()该特定的任意链接将是前一链接。该方法在定位其中正向指针。这是必须首先被阻挡的链接指针,并且最后指向新插入的链接,该链接将紧接着在特定的任意链接之后。执行插入一个链接,普通非原子过程中的步骤,传递一个指向在特定的任意链接中的正向指针的引用。
insertAfterCurrentLink()如果变元的当前链接是NULL,则该函数必然失败。否则,它使用如下步骤来尝试紧接着在当前链接之后插入新的链接。该函数可能失败,把新的当前链接留给该变元,但是保持“它在链中的位置”。
(a)在变元观察对象702中的curLink字段706指向当前链接。变元尝试阻挡在当前链接中的正向指针。它等待并且在必要时重新尝试阻挡,直到该链接指针不被尝试删除该链接的变元所阻挡。如果阻挡尝试成功完成,则继续到步骤(b)。否则阻挡尝试失败,因为另一个变元已经阻挡该链接指针并且要删除包含它的链接(该变元的当前链接)。其它(阻挡)变元也会阻挡在(该变元curPtr 705所指向的)前一链接中的正向指针。该阻挡变元将不知道这个变元阻挡该链接指针失败,而可能(最终)把它简单的看作为附加到受阻链指针上的迭代变元,并且如果这样的话,则将等待它前进。为了避免死锁,这个变元观察对象被移出阻挡变元的路。为了完成该操作,不是向前进,而是这个变元的观察对象被改变,使得它刚好前进到(curPtr所指向的)前一链接中的受阻正向指针。如果必要的话,它把它已经前进的情况通知给该阻挡变元,然后等待该阻挡变元解阻挡它的链接指针。当阻挡变元解阻挡它们时,它将看到这个等待的变元观察对象,并且将把其中的curLink 706设置为指向它的新的当前链接(完成它的前进),并且将唤醒它(就象它对等待在受阻链接指针上的任何迭代变元所做的那样)。当被唤醒时,这个变元将保留在链中的相同位置(即,在其观察对象中的curPtr705将不改变),但是由于它将具有新的当前链接,因此重新尝试插入函数是没有意义的。相反,它退出并向调用getCurrentLink()函数的客户返回一个失败指示,该客户检验新的当前链接并确定从那里做些什么。
(b)如果变元不保留其当前链接,则变元的观察对象被复位。如果它要得到一个新的当前链接,则这将在以后重新建立。
(c)该方法阻挡在下一个链接中的反向指针,等待并且在必要时重新尝试,直到它被成功阻挡为止。(如果下一个链接是NULL,则取而代之的是它阻挡在SharedChain对象中的最后链接指针字段603)。但是,如果要被阻挡的链接指针被另一个变元尝试性地阻挡,则它不尝去试阻挡该链接指针。取而代之的是,它使用链接传送机制(在下文中具体描述)来等待来自其它变元的许可以使用该链接指针。(该其它变元将使用该链接传送机制来暂停对该链接指针的阻挡,并且将给出使用它的许可,并且然后等待重新开始的许可)。
(d)以步骤11为开始执行插入一个链接,普通非原子过程的步骤。
insertLast()该方法定位在SharedChain对象中的最后链接指针字段603。这是将最终指回到新插入的链接的链接指针,该链接将是在该链中的最后链接。从步骤6开始执行插入一个链接,普通非原子过程,传送一个指向在SharedChain对象中的最后链接指针字段603的引用。
insertBeforeArbitraryLink()该特定的任意链接将是下一个链接。该方法定位其中的反向指针。该链接指针将最终指回新插入的链接,该链接紧接着在该特定的任意链接之前。从步骤6开始执行插入一个链接,普通非原子过程,传送一个指向在该特定任意链接中的反向指针的引用。
insertBeforeCurrentLink()如果该变元在无效状态,则没有插入该新链接的位置,并且该函数必然失败。否则,使用如下步骤来尝试紧接着在当前链接之前插入该新的链接。这个函数可能失败,并且把一个新的当前链接留给该变元,但是保持“其在链中的位置”。
(a)在变元观察对象中的curPtr字段705指向前一链接中的正向链接指针。变元尝试阻挡该链接指针,但是它不重新尝试或等待成功。如果阻挡尝试成功完成,则继续到步骤(b)。否则阻挡尝试失败,因为另一个变元已经阻挡该链接指针。其它(阻挡)变元将不知道该变元阻挡该链接指针失败,并且可能(最终)把它简单的看作为附加到受阻链指针上的迭代变元,并且如果这样的话,则将等待它前进。为了避免死锁,该变元观察对象被移出阻挡变元的路。为了完成该操作,不是向前进,而是这个变元的观察对象被改变,使得它好像刚好前进到受阻链接指针,如果必要的话,该阻挡变元被通知关于该变元已经前进的情况。然后这个变元等待该阻挡变元接通它的链接指针。如果该受阻链接指针被要删除包含该指针的链接的变元所阻挡,则它还将阻挡在前一链接中的正向指针。这种情况下,该变元的观察对象被删除,从而它好像刚好前进到该前一指针,并且如果必要的话,该阻挡变元被通知关于该前进的情况。然后这个变元等待阻挡变元接通其链接指针。在此时,阻挡变元将看到这个等待变元的观察对象,将把其中的curLink 706设置为指向要被删除的链接之后的链接(完成其前进过程),并且将把其唤醒,就象对如何等待受阻链接指针的迭代变元所作的那样。当被唤醒时,这个变元将具有一个新的curPtr 705,但是将具有相同的curLink 706。然后通过返回到步骤(a)的开始处重新尝试插入。但是,如果受阻链接指针被不要删除包含该指针的链接的变元所阻挡,这个变元的观察对象被移动,使得它看起来刚好前进到该受阻链接指针,并且如果必要的话,该阻挡变元被通知该前进的情况。然后,这个变元等待该阻挡变元接通其链接指针。在此时,该阻挡变元将看到这个等待变元的观察对象,将把在其中的curLink 706设置为指向在被删除的链接之后的链接(完成其前进过程),并且将唤醒它,就象对等待受阻链接指针的任何迭代变元所作的那样。当被唤醒时,这个变元将保持在该链中相同位置(即,在其观察对象中的curPtr 705将保持不变),但是由于它将具有一个新的当前链接,因此重新尝试插入函数没有意义。替代地,退出并向客户返回一个失败指示,该客户可以调用getCurrentLink()函数并且检验新的当前链接和确定要从此处开始进行的操作。
(b)在这一点,在前一链接中的正向指针已经被成功阻挡。如果该变元保留它的当前链接,则在其观察对象中的curPtr字段被改变为指向被插入的链接中的正向指针(这是安全的,因为还没有其它迭代器可以看见该新的链接)。否则,变元的观察对象被复位,使得它不再具有当前链接。需要避免潜在的死锁,并且当前链接不再需要识别那一个链接之前要被插入。如果需要的话,变元的当前链接可以被重新建立。
(c)变元阻挡在(以前的)当前链接内的反向指针,需要时等待和重新尝试,直到成功阻挡。(如果(以前的)当前指针为NULL,取而代之的是它阻挡在SharedChain对象内的最后链接指针字段603)。但是,如果要阻挡的链接指针被另一个变元暂时阻挡,则它不尝试阻挡该链接指针。而是,它使用链接传送机制(在下文中具体描述)等待来自另一个变元的许可,以使用该链接指针。(其它变元将使用链接传送机制,以把其阻挡悬置在链接指针上,并且将给出使用它的许可,然后将等待许可恢复)。
(d)执行插入一个链接,普通非原子过程中的步骤。插入一个链接,普通非原子过程这是上述函数的继续。有几个开始点insertFirst()以及insertAfterArbitraryLink方法在步骤1开始,具有对作为输入参数传送的在前一链接中的正向指针的引用,而insertLast()和insertBeforeArbitraryLink()方法在步骤6开始,具有对作为输入参数传送的下一链接中的反向指针的引用。insertBeforeCurrentLink()和insertAfterCurrentLink()方法在步骤11开始。
1.变元被复位以保证它没有当前链接。需要避免死锁。如果需要的话,变元的当前链接可以重新建立。
2.变元阻挡在前一链接中的正向指针,等待并在必要时重新尝试直到成功阻挡为止。阻挡这个指针把一个指针返回到该列表中的下一链接,并且它还原子地将指向那个链接的一个指针存储在该阻挡元对象内的下一链接字段802中。新的链接将被插入在前一链接和下一链接之间。
3.在下一链接中的反向指针被定位。但是,如果下一链接是NULL,则它定位在SharedChain对象中的最后链接指针字段603。
4.变元阻挡在步骤3中定位的链接指针,等待并且在需要时重新尝试直到成功阻挡为止。但是,如果该链接指针被另一个(阻挡)变元暂时阻挡,则它不尝试阻挡该指针。而是,它使用链接传送机制来等待来自该阻挡变元的许可,以使用该连接指针。(该阻挡变元将使用链接传送机制来暂停它对该链接指针的阻挡,对这个变元给予许可使用该指针,并且将等待许可恢复)。
5.继续到步骤11。
6.该变元被复位,以保证它没有当前链接。这需要避免死锁。如果需要的话,变元的当前链接可以在以后重新建立。
7.变元阻挡在下一链接内的反向指针,等待并且在必要时重新尝试,直到成功阻挡为止。阻挡这个链接指针把一个指针反回到前一链接。该阻挡是暂时的,并且如果在步骤4尝试的阻挡还没有成功,则将悬置。在受阻链接指针(未在图中示出)中的标志表明它被暂时地阻挡)。
8.在前一链接中的正向指针字段被定位。但是,如果前一链接为NULL,则取而代之的是在SharedChain对象内的第一链接指针字段被定位。
9.变元尝试阻挡在步骤8中定位的链接指针,但是不重新尝试或等待它的成功。如果该阻挡尝试成功,则继续到步骤10。否则,由于该链接指针已经被另一个(阻挡)变元所阻挡,因此该阻挡尝试失败。该阻挡变元或者删除前一链接,或者在其后插入新的链接。在任何一种情况中,阻挡变元将最终需要阻挡在步骤7中被暂时阻挡的链接指针。当它确定该链接指针被暂时阻挡时,则它将使用链接传送机制等待许可来使用它。这个变元使用链接传送机制来悬置该链接指针,许可阻挡变元使用它,并且保持在步骤7中所做的阻挡。在许可使用受阻链接指针时,它把一个指向前一链接的指针给予阻挡变元。然后,这个变元使用链接传送机制等待阻挡变元结束,在结束时它将给出恢复的许可,把一个指向新的前一链接的指针传回。利用指向新的前一链接的指针,这个变元回到步骤8重新尝试阻挡在其中的正向链接指针。
10.在这一点,在前一链接的正向指针中的阻挡已经成功完成,并且指向下一链接的指针已经被原子地设置在阻挡元对象中下一链接字段802内。不再有任何原因使得在步骤7中所做的阻挡为尝试性的,从而在受阻链接指针中的一个标志被设置为关闭,表示它不再是尝试性的。
11.在该链中的链接的计数值被增加。
12.在新的链接中的正向和反向指针被分别设置为指向下一个和前一个链接。如果被定义,则可选的链指针字段被设置为指向SharedChain对象。
13.阻挡元的下一链接字段802被设置为指向新的链接。此后,遇到前一链接内的受阻正向链接指针的任何检查元将看到新的链接。
14.变元等待任何前进的非原子迭代器(检查元或变元),该迭代器取决于受阻的正向链接指针,以前进超过它。是迭代器在受阻挡之前到达正向链接指针,或者是检查元在前进通过受阻链接指针到达下一个(不是新的)链接过程中。
15.执行插入或删除一个链接,普通非原子过程中的步骤以完成插入过程。删除一个链接,非原子方法参见图10,为了从链中删除一个链接,有4个必须首先被阻挡的链接指针(a)在前一链接中的正向指针1002;(b)在被删除的链接内的反向指针1003;(c)在被删除的链接内的正向指针1004;以及(d)在下一链接内的反向指针1005。在前一链接中的正向指针上的阻挡是关键阻挡。一旦该阻挡完成,它确定要被删除的链接。
图10示出用于已经阻挡从链中删除“链接B”所需的链接指针的变元的阻挡元对象。受阻挡的链接指针都指向阻挡元对象,并且x01位被设置开启(on)。(另外,在被删除的链接中的正向指针1004具有也被设置为开启的x08数位,以表示它在正在被删除的链接中)。在阻挡元对象中的下一链接字段802指向“链接C”,使得遇到“链接A”或“链接B”内的受阻正向指针的非原子检查元将跳过“链接B”并且将看到作为下一个链接的“链接C”。在阻挡元对象中的前一链接指针字段1001指向“链接A”中的正向指针。一些情况中这被遇到“链接B”内的受阻正向指针的迭代变元所使用,并且需要把curPtr移回到“链接A”中的正向指针,以在“链接B”被删除之后,把“链接C”看作为它们的新当前链接。
有各种可以从链中可以删除链接的函数。它们都被认为是前端(front_end)以阻挡在前一链接中的正向指针,然后执行在删除一个链接,普通非原子过程中所述的步骤,以阻挡剩余的链接指针并且删除该链接。
removeFirstLink()变元的观察对象首先被复位以保证它没有当前链接。这是避免潜在的死锁的需要。如果需要的话,可以重新建立变元的当前链接。然后,变元阻挡在SharedChain对象类的第一链接指针字段602,等待并且在需要时重新尝试,直到成功阻挡为止。阻挡该链接指针返回一个指向该链中的第一链接的指针,该链接是要被删除的链接。然后执行删除一个链接,普通非原子过程,传送一个到受阻的链接指针的观察对象的引用。
removeAfterArbitraryLink()变元被首先复位以保证它没有当前链接。被指定的任意链接将是前一链接。变元阻挡其中的正向指针,等待并且在需要时重新尝试,直到成功阻挡为止。阻挡该链接指针返回一个指向紧接着在任意链接之后的链接,并且该链接是要被删除的链接。然后执行删除一个链接,普通非原子过程,传送一个到受阻的链接指针的引用。
removeArbitraryLink()由于该列表的变元的非原子观察,多少有一点涉及到了定位前一链接而阻挡其正向指针。执行如下步骤
(a)变元的观察对象被复位,以保证它没有当前指针。
(b)变元阻挡在要被删除的任意链接内的反向指针,等待并且在必要时重新尝试,直到成功阻挡为止。阻挡该链接指针返回一个指向前一链接的指针。该阻挡是尝试性的,并且如果在步骤(d)中尝试的阻挡还没有成功,则它被暂停。在受阻链接指针中的一个标志(未示出)标识它被尝试性地阻挡。
(c)在前一链接中的正向指针被定位。但是,如果前一链接为NULL,则取而代之的是在SharedChain对象中的第一链接指针字段602被定位。
(d)变元尝试阻挡在步骤(c)中定位的链接指针,但是不重新尝试或者等待成功。如果该阻挡尝试成功,则继续到步骤(e)。否则,由于链接指针已经被另一个(阻挡)变元所阻挡,从而该阻挡尝试失败。阻挡变元或者删除前一链接,或者在它之后插入新的链接。两种情况中,它将最终需要阻挡在步骤(b)中尝试性地阻挡的链接指针。当阻挡变元确定该链接指针被尝试性地阻挡,则它将使用链接传送机制等待使用该链接指针的许可。该变元使用链接传送机制来暂停受阻的链接指针,许可阻挡变元使用它,而保持在步骤(b)中完成的阻挡。在接收使用受阻链接指针的许可时,阻挡变元被给予一个指向前一链接的指针。然后,使用链接传送机制,这个变元等待阻挡变元结束,在结束的时候阻挡变元给出重新开始的许可,把一个指向新的前一链接的指针传回。利用指向新的前一链接的指针,该变元返回到步骤(c),重新尝试阻挡其中的正向指针。
(e)在这一点,在前一链接中的正向指针的阻挡已经成功完成,并且不再有任何原因使得在步骤(b)中进行的阻挡为尝试性的。在受阻挡的链接指针中的标志被设置为关闭,使得它不再是尝试性的。
(f)然后执行在删除一个链接,普通非原子过程中的步骤,传送一个到受阻的链接指针的引用。
removeCurrentLink()如果变元的当前链接是NULL,则没有要删除的链接,并且该函数必然失败。否则,该函数执行如下步骤尝试删除当前链接。该函数可能失败,而把一个新的当前链接留给变元,但是保持“其在链中的位置”。
(a)在变元的观察对象中的curPtr字段705指向前一链接中的正向链接指针。该变元尝试阻挡该链接指针,但是不重新尝试或等待成功。如果阻挡尝试成功,则继续到步骤(b)。否则,由于另一个(阻挡)变元已经阻挡该链接指针,因此阻挡尝试失败。阻挡变元将不知道这个变元尝试阻挡链接指针的失败,但是可能(最终)把它简单地看作为附加到受阻挡链接指针的迭代变元,如果这样的话,将等待它前进。为了避免死锁,这个变元的观察对象被移出阻挡变元的路。为此,不是向前进,而是这个变元的观察对象被改变,使得它看起来刚好前进到受阻挡链接指针,并且如果需要的话,阻挡变元被通知它前进的情况。然后,这个变元等待阻挡变元解阻挡其链接指针。如果受阻连接指针被要删除包含该指针的链接的变元所阻挡,则它也将阻挡在前一链接中的正向指针。在这种情况下,这个变元的观察对象被移动,使得它看起来刚好前进到该前一指针,如果必要的话,阻挡变元被通知该前进的情况。然后,这个变元等待阻挡变元解阻挡其链接指针。在此时,阻挡变元将看到这个等待变元的观察对象,将把其中的curLink706设置为指向跟随在被删除的链接之后的链接(完成它的前进过程),并且将唤醒它,就象对任何等待于受阻链接指针上的迭代变元所做的那样。当被唤醒时,这个变元将具有新的curPtr 705,但是将具有相同的curLink 706。然后通过返回到开始步骤(a)重新尝试删除。但是,如果受阻链接指针被不要删除包含该指针链接的一个变元所阻挡,则这个变元的观察对象被移动,使得它看起来象刚好前进到受阻的链接指针,并且如果必要的话,阻挡变元被通知该前进的情况。然后,这个变元等待阻挡变元解阻挡其链接指针。在此时,阻挡变元将看到这个等待变元的观察对象,将把其中的curLink 706设置为指向该被删除链接之后的链接(完成其前进过程),并且将唤醒它,就象对任何等待于受阻链接指针上的迭代变元所做的那样。当被唤醒时,这个变元将保持在链中的同一位置(即,在其观察对象中的curPtr将不改变),但是由于它将具有新的当前链接,因此重新尝试删除函数没有意义。而是,退出并向调用getCurrentLink()函数的客户返回一个失败指示,该客户检查新的当前链接而且确定要做的工作。
(b)在这一点,在前一链接中的正向指针已经被成功地阻挡。变元的观察对象被复位,使得它不再具有当前链接。需要避免潜在的死锁,并且当前链接不再需要识别要被删除的链接。如果需要的话,变元的当前链接可以在以后被重新建立。
(c)然后执行删除一个链接,普通非原子过程中的步骤,传送一个被阻挡的链接指针的引用。
removeAfterCurrentLink()如果变元的当前链接是NULL则该函数必然失败。否则,该函数执行如下步骤尝试删除当前链接后的链接。该函数可能失败,而把一个新的当前链接留给变元,但是保持“其在链中的位置”。
(a)在变元的观察对象中的curLink字段706指向当前链接。该变元尝试阻挡该当前链接中的正向链接指针。它等待并且在需要时重新尝试阻挡,直到该链接指针没有被要删除该链接的变元所阻挡。如果阻挡尝试成功,则继续到步骤(b)。否则,由于另一个(阻挡)变元已经阻挡该链接指针并且要删除包含它的链接(该变元的当前链接),因此阻挡尝试失败。阻挡变元还将阻挡在(curPtr所指向的)前一链接中的正向指针。该阻挡变元将不知道这个变元尝试阻挡链接指针的失败,但是可能(最终)把它简单地看作为附加到受阻挡链接指针的迭代变元,如果这样的话,将等待它前进。为了避免死锁,这个变元的观察对象被移出阻挡变元的路。为此,不是向前进,而是这个变元的观察对象被改变,使得它看起来刚好前进到(curPtr 705指向的)前一链接中的正向指针,并且如果需要的话,阻挡变元被通知它前进的情况。然后,这个变元等待阻挡变元解阻挡其链接指针。当解阻挡时,它将看到这个等待变元的观察对象,将把其中的curLink设置为指向这个变元的新当前链接(完成其前进过程),并且将唤醒它(就象对任何等待于受阻链接指针上的迭代变元所做的那样)。当被唤醒时,这个变元将保持在链中的相同位置(即,在其观察对象中的curPtr将不改变),但是由于它将具有新的当前链接,因此重新尝试删除函数没有意义。而是,退出并向调用getCurrentLink()函数的客户返回一个失败指示,该客户检查新的当前链接而确定要做的工作。
(b)如果该变元不保留其当前链接,则变元的观察对象被复位。如果它具有新的当前链接,这将在以后被重新建立。
(c)然后执行删除一个链接,普通非原子过程中的步骤。删除一个链接,普通非原子过程至此,对前一链接中的正向指针的引用被作为一个输入参数而传送。这个链接指针已经被阻挡,原子地识别要被删除的链接,并且设置在阻挡元对象中的下一链接字段802,以指向要被删除的链接。遇到受阻挡的正向链接指针的检查元可以前进通过它,以查找被删除的链接。如果指向要被删除的链接的指针为NULL,则没有链接要被删除。在这种情况下,如下步骤被跳过,并且该处理继续到插入或删除一个链接,普通非原子过程,以解阻挡在前一链接中的正向指针,并且退出。否则,执行如下步骤以删除链接。
1.该变元定位在被删除的链接中的反向指针1003,并且如果该变元还没有阻挡它,则现在阻挡它,并且在必要时重新尝试。该变元已经阻挡它的唯一情况将是删除一个任意链接。(请注意,如果反向链接指针被一些其它变元所阻挡,则没有等待被解阻挡的死锁首先,它可能还没有被尝试性地阻挡,由于能够尝试性阻挡在一个链接(不是在SharedChain对象中的最后链接指针字段603)中的反向指针的函数是把该链接引用为一个任意链接的函数,并且这将是一个无效的工作,因为该链接正在被删除。其次,任何阻挡在链接中的反向指针的变元将已经阻挡在前一链接中的正向指针,并且因为不再有这种情况,则唯一的可能是该变元已经解阻挡在前一链接中的正向链接指针并且要解阻挡在此感兴趣的反向指针)。
2.指向前一链接的阻挡正向指针1002的指针被存储到阻挡元对象中的前一链接指针(previous_link_pointer)字段1001。一旦该链接指针被在步骤3中阻挡,则这将是需要的,以使得其它迭代变元备份以脱离被删除的链接。
3.该变元定位在被删除的链接中的正向指针1004,并且阻挡它。阻挡该链接指针返回一个到下一个链接的指针。它还设置在阻挡元对象中的下一链接字段802也指向下一链接,从而此后非原子的检查元可以前进通过受阻挡链接指针,以定位下一个链接,跳过正被删除的链接(在阻挡该链接时,如果需要等待,则有一个专用的接口来完成该操作,则再次涉及链接传送机制,如下文中更加具体描述)。
4.该变元等待任何前进的非原子迭代器(检查元或变元),该迭代器取决于受阻挡的链接指针,以前进超越它们。这些将是在链接指针被阻挡之前前进到受阻链接指针的迭代器。
5.在下一链接中的反向指针1005被定位。但是,如果下一链接是NULL,则被删除的链接是该列表中的最后链接。在这种情况下,在SharedChain对象中的最后链接指针字段603被定位。
6.变元阻挡在步骤5中定位的链接指针,等待并且在需要时重新尝试,直到成功阻挡为止。但是,如果该链接指针被另一个变元尝试性地阻挡,则它不尝试阻挡该链接指针。而是,它使用链接传送机制来等待使用该链接指针的许可。(已经进行阻挡的变元将使用链接传送机制来暂停其在链接指针上的阻挡,给予使用它的许可,然后等待恢复的许可)。
7.在链中的链接计数值被减小。
8.在要被删除的链接中的正向和反向链接指针(以及可选的链指针,如果被定义的话)被设置为NULL。
9.执行插入或删除一个链接,普通非原子过程的步骤,以结束删除处理。插入或删除一个链接,普通非原子过程1.在这一点,如果需要的话用于该变元的一个新的当前指针可以被建立(或者重新建立)。变元的观察对象可以安全附加到该链上的唯一位置是在前一链接中的受阻正向链接指针。curPtr字段705可以被设置为指向正向链接指针,并且curLink字段可以被设置为指向当它后来被解阻挡时该正向指针将指向的链接。更具体来说,如果一个链接被删除,则变元的当前链接可以被设置为指向紧接着在被删除的链接之后的链接(下一个链接);如果一个链接被插入,则变元的当前链接可以被设置为指向新插入的链接。(请注意对于insertAfterCurrentLink()或者removeAfterCurrentLink()函数,该变元可能保留其当前链接。它可能原封不动,或者可能改变为指向新插入的链接或者跟随在被删除的链接之后的链接。(或者如果需要的话,替代地该变元可能被复位到无效状态)。
2.在前一链接中的正向链接指针被解阻挡,把它改变为下一链接(如果一个链接被删除)或者指向新的链接(如果一个链接被插入)。解阻挡该链接指针,原子地改变它,当它被阻挡时返回它所包含的数值。受阻的链接指针包含附加的标志,其表示是否其它迭代或阻挡变元等待要被解阻挡的链接指针。但是,需要考虑一种特殊情况。如果要删除包括受阻的正向链接指针的链接的阻挡变元等待要被解阻挡的链接指针,则该链接指针不被解阻挡。替代地,受阻的正向链接指针被(原子地)更新,使得它现在看起来被其它(指向其阻挡元对象并且x09位开启的)变元所阻挡,该其它变元要删除包含它的链接。然后链接传送机制被用于给予该变元使用该链接指针的许可,把指向下一链接的指针传送给它(否则当解阻挡它时该数值已经被置于链接指针中)。
3.在下一链接中的反向链接指针被解阻挡,把它改变为指向前一链接(如果该链接被删除)或者指向新的链接(如果一个链接被插入)。解阻挡该链接指针原子地改变它,当它被阻挡时返回它所包含的数值。受阻挡链接指针包含附加的标志,其表示其它阻挡变元等待该链接指针被解阻挡。但是,如果该链接指针不被该变元所阻挡,而是由一些其它变元尝试性地阻挡,则该链接指针必然不被解阻挡。而是,其它变元将暂停使用该链接指针,并且将等待重新开始的许可。在这种情况下,链接传送机制被用于给予该变元重新使用的许可,把一个指向将做为新的前一链接的指针传送给它(否则当解阻挡它时该数值已经被置于该链接指针内)。(当删除一个链接有多种情况,其中在阻挡前一链接中的正向链接指针之后,确定没有要被删除的链接。在这些情况中,在下一链接内没有受阻挡的反向链接指针,从而该步骤应该被完全跳过。)4.如果有等待在前一链接中的正向链接指针被解阻挡的迭代变元,则它们现在被唤醒。它们都可以通过在观察对象701的列表中搜索位于SharedChain对象内的非原子变元而找到。
5.如果存在等待任何一个链接指针被解阻挡的阻挡变元,则它们现在被唤醒。并且它们都可以通过从位于SharedChain对象内的指针803开始搜索阻挡元对象的列表而找到。
6.在此时,插入或删除函数完成。一旦所有其它检查元和被唤醒的变元不再具有对阻挡元对象的引用,则它可以被重新用于另一个改变函数。对非原子变元当前链接的考虑为了避免死锁,非原子变元必须被复位(或者至少它的观察对象必须被内部复位)使得它在执行改变函数时没有当前链接(除了insertAfterCurrentLink()和removeAfterCurrentLink()函数之外)。变元通过改变函数“保持它在链中的位置”的唯一方式是在该函数完成时使它重新建立一个新的当前链接。并且可以安全地变为新的当前链接的唯一链接是允许变元“保持其位置”的一个链接。变元的状态可以用在以前定义的MutatorControl数值来控制。
链接表结构内部细节这一部分描述非原子观察与阻挡元对象之间以及阻挡元对象之间的交互作用的详细情况。不是采用在上文中的内部操作部分中所述的更大图形来描述,本部分将针对于各个独立的交互作用。可以参照内部操作部分,来看看特定的交互作用适用该大图形的位置。为了进一步有助于理解所述的实施例,使用了一些附加的例子和图形。数据区域和定义链接指针如上文所述,在链中的链接的地址为多个字节,使得至少N个低阶数位为0(在优选实施例的环境中,N为4,字节数目为16,应当知道可以使用其它数值,或者例如专用的标志字段这样的其它机制可以被用于取代地址中的标志)。在阻挡元对象的地址中的相同的N位也为0,并且它们被用作为标志。表9描述在该链中的链接指针内的每个标志位的含义。
表9在链接指针中的标志位的含义
x01 受阻挡链 当开启时,该标志表示链接指针被阻挡,并且接指针 屏蔽低阶N数位将产生指向属于阻挡它的变元的阻挡元对象的指针。当该数位开启时,剩余的标志位仅仅为开启。x02 迭代变元 当开启时,该标志表示至少一个迭代变元等待等待 (或者准备等待)该链接指针被解阻挡。当解阻挡变元解阻挡该链接指针并且看到该标志时,它在观察对象的列表中搜索非原子变元,并且唤醒任何已经表明要等待该链接指针被解阻挡的任何变元。该标志仅仅被用于正向链接指针中。x04 阻挡变元 当开启时,该标志表示至少一个阻挡变元等待等待 (或者准备等待)该链接指针被解阻挡。当解阻挡变元解阻挡该链接指针并且看到该标志时,它在阻挡元对象的列表中搜索并唤醒任何已经表明要等待它解阻挡其链接指针的任何变元。该数位可以被用于正向或反向链接指针中。在正向链接指针中,它还具有与下文中所述的x08数位相结合的特殊含义。x08 尝试性阻 当在反向链接指针中开启时,该标志表示存在挡 于链接指针上的阻挡是尝试性的,并且可能被暂停。x08 删除暂停 当在正向链接指针中开启时,该标志表示包含正向指针的链接要被删除。要删除该链接的变元已经(还)阻挡在前一链接中的正向指针。该数位的具体含义取决于x04位的设置如果x04位为关闭,则它意味着已经阻挡该链接指针的变元是要删除该链接的变元。
如果x04位为开启,则它意味着等待阻挡该链接指针的变元(在此可能仅仅有一个)要在它成功阻挡该链接指针时删除该链接。
根据该链接指针的已知当前数值,原子地更新链接指针。在优选实施例中,一个称为compareAndSwap()的特殊系统函数被用于作此操作。另外,在一些情况中,一个被称为compareAndSwapQualitied()的特殊系统函数被使用;后面的函数执行单个指针的交换(swap),并且还比较存储器(一个4倍长字)的较大片断,如果存储器的较大片断的任何部分已经在操作过程中改变,则提供一个失败指示。类似的函数被用于其它系统中,或者在链接指针更新操作过程中可以采用其它原子的方法。非原子观察对象当一个非原子迭代器(检查元或变元)处于有效或过渡状态,则存在与其相关的一个观察对象。该观察对象包含跟踪迭代器的当前链接的两个字段。当迭代器前进通过该链时,这些字段必须用很好定义的方式更新。由于变元可能在任何时间阻挡和解阻挡链接指针,因此在所有时间点它们必须知道,并且需要确定是否给定的观察对象是否有利害关系。
curPtr 705该字段包含指向正向链接指针的指针。该正向链接指针或者位于当前链接中,或者位于前一链接中。在优选实施例中,在链接内所有链接指针都在一个8字节边界上,因此至少它们地址的低3位为0。在curPtr字段内,这些数位被用作为如表10中所定义的标志。
表10在curPtr中的标志位的含义
x01 承诺的等 当开启时,该标志表示已经阻挡curPtr所指待者 向的链接指针的变元已经承诺等待该观察对(committed象所属的迭代器,来前进超过该被阻挡的链接waiter) 指针。x02 优先级冲仅仅当x01标志位为开启时该标志才开启。
突(priority 当开启时,它表示承诺等待迭代器的变元已bumped) 经与迭代器任务的优先级相冲突x04 删除等待仅仅当x01标志位为开启时该标志才开启。当(remove 开启时,它表示等待变元要删除作为迭代器的waiting)当前链接的链接。在这种情况下,该迭代器将延迟把前进的情况通知该变元,直到它前进两个链接时为止(技术上,直到它已经作出对curPtr的两次更新时为止)。
curLink 706该字段包含指向迭代器的当前链接的指针。由于链接必然在一个16字节链接上,因此在它们地址中的至少4个低阶位为0。在curLink字段中,3个数位被用作为如表11中所定义的标志。
表11在curLink中的标志位的含义
x01 承诺的等当该标志开启时,它表示迭代器已经遇到一个待者受阻链接指针,并且已经承诺等待它被解阻挡。当该数位为开启时,curLink(屏蔽4个低阶数位)不是指向该列表中的一个指针,而是指向属于已经阻挡由curPtr所定位的正向链接指针的变元的阻挡元对象。这个标志只会在变元的观察对象中开启;检查元可以前进通过受阻的链接指针,而没有等待。x02 优先级冲仅仅当x01标志位为开启时该标志才开启。当突 开启时,它表示等待的迭代器已经与阻挡变元的任务的优先级相冲突。x04 优先级无仅仅当x01标志位为开启时该标志才开启。当冲突开启时,它表示等待迭代器已经决定不需要冲撞阻挡变元的任务的优先级。
除了上述数位标志之外,还有两个可能出现在curLink字段706中的特殊数值。
表12在curLink中的特殊数值
x00...02 过渡 该特殊数值表示在推进迭代器的过程中,(transition) curPtr已经被设置,但是解除引用curPtr的结果还没有设置在curLink中。看到在curLink中的该数值的阻挡变元将不能够得知是否已经出现curPtr的解除引用。x00...04错误比较 当刚刚阻挡或解阻挡curPtr所指向的链接(miscompare)指针的变元看到curLink中的过渡数值时,
它不能(从变元的角度来看)区分这是前进迭代器要存储到curLink中的链接指针的旧数值还是新数值。因此该变元在迭代器把从curPtr解除引用的结果存储之前把curLink改变为错误比较数值,以使得迭代器的存储尝试失败。当迭代器不能改变curLink时,则它将在再次存储之前解除引用curPtr。按照这种方式,变元可以保证迭代器将从curPtr解除引用并存储在curLink中的数值。
这些字段被通过compareAndSwap()函数原子地更新。由于该函数不能把更新两个字段作为单个原子操作,因此使用在一次更新单个字段的compareAndSwapQualified()函数,但是如果在同时更新任何其它字段,则将失败。
另外,一个非原子观察对象具有一个优先级冲突不确定性解决器对象(priority_bump_uncertainty_resolver object)。这是一个单任务阻挡元对象,即仅仅影响一个任务的同步机制。它在不确定一个变元是否已经冲突迭代器的任务的优先级时使用,以等待直到优先级冲突被确定为止。完成该操作以避免在可能的优先级冲突之前出现可能的优先级冲突解决(priority unbump)。阻挡元对象当一个变元(原子或非原子)执行改变函数时,存在与它相关的阻挡元对象。该阻挡元对象包含定义其状态的几个字段有效Id(activation Id)每次一个阻挡元对象被分配给一个变元时,该字段被分配一个唯一的数字(对SharedChain对象唯一)。如果检查元看到一个链接指针被阻挡,则当它第二次查看其是否(仍然)被阻挡时,它可以把有效Id字段相比较,以得知它是否仍然被阻挡或者第二次被阻挡。该字段在变元使用阻挡元来阻挡任何链接指针之前被分配。
下一链接(next link)该字段包含指向该列表中的下一链接的指针,并且最初允许检查元前进通过受阻挡正向链接指针。该字段实际上包含两个字段主要和次要字段。这两个字段在一个链接被删除时都需要,以使得为一个链接被删除时该字段看起来被原子地设置。当一个迭代器前进到下一个链接,并且遇到受阻挡链接指针,则它通常应当使用主要字段来查找下一个链接。但是,如果受阻挡链接指针在被阻挡该指针的变元所删除的一个链接内时,则该变元应当使用次要字段来查找下一个链接。
等待阻挡元(waiting for blocker)该字段用于表示使用阻挡元对象的变元等待使用第二阻挡元对象的第二变元,来解阻挡其链接指针。通常,该字段包含NULL,以表示该变元没有等待。当等待或准备在第二变元等待时,一个指向第二变元的阻挡元对象的指针被存储在该字段中。阻挡元对象的地址的低N位为0。则该字段中,3个低阶位被用作为标志。表13描述当一个阻挡元地址被存储时的几个标志位。
表13等待阻挡元标志位
x00 不承诺当所有标志位都关闭时,该变元准备等待第(uncommitted) 二变元,但是还没有承诺等待。x01 承诺 当该标志位开启时,该变元承诺等待第二变(committed) 元。x02 优先级冲突仅仅当x01标志位为开启时该标志才开启。
(priority 当开启时,它表示变元已经与第二变元的任bumped) 务的优先级相冲突。x04 优先级无冲突 仅仅当x01标志位为开启时该标志才开启。
(priority not 当开启时,它表示变元已经决定不需要冲突bumped) 第二变元的任务的优先级。
前一链接指针(previous link pointer)仅仅当使用阻挡元对象的变元删除一个链接时才使用该字段。在阻挡前一链接中的正向指针之后,它把一个指针存储到该字段中的链接指针,然后继续阻挡要被删除的链接中的正向指针。由于发现要被第一变元(该变元要删除包含curPtr所指向的正向指针的链接)所阻挡的curPtr而导致尝试删除其当前链接或者在它之前插入链接失败的第二变元将必须把curPtr改变为指向前一链接中的正向指针。该字段使得迭代变元在前一链接中查找正向指针。
状态控制(status control)这是一个状态计数器对象,即由特定事件所增减的计数器,并且根据它的任务可能等待该计数值到达特定数值。这是控制阻挡元和非原子观察对象之间的等待/唤醒交互作用的主要机制。这在下文中更加具体描述。
暂停的链接控制(suspended link control)这也是一个状态计数器对象。它是当用于暂停的链接指针时链接传送机制的心脏。这在下文中更加具体描述。
受阻的删除控制(blocked remove control)这也是一个状态计数器对象,它是当删除一个链接时的链接传送机制的心脏。这在下文中更加具体描述。
优先级冲突计数(priority bump count)该字段被用于累计等待者已经冲突变元任务的优先级的次数。在所有等待者被唤醒之后,变元将最终以该次数解决其自身优先级的冲突。非原子观察和阻挡元交互作用情况图11示出用于两个迭代变元的观察对象和用于两个阻挡变元的阻挡元对象的交互作用的例子,所有都作用于相同的链接指针。将出现如下情况1.使用观察对象1101的变元第一个到达“链接A”内的正向指针1111,使得“链接B”成为其当前链接。其curPtr字段1112指向“链接A”内的正向指针1111,并且其curLink字段1113字段指向“链接B”。
2.使用阻挡元对象1103的变元下一个到达,要把一个链接插入在“链接A”和“链接B”之间,并且阻挡在“链接A”中的正向指针1111,设置开启在此的x01阻挡链接指针(blocked_link_pointer)标志。然后它查看所有观察对象,发现附加到同一正向链接指针的观察对象1101,并且设置开启在curPtr1112中的x01承诺等待者和x02优先级冲突标志,使其等待拥有观察对象1101的迭代器前进,并且表示它已经与迭代器任务的优先级相冲突。
3.同时,使用观察对象1102的变元到达“链接A”中的正向链接指针1111(把其curPtr字段1114设置为指向它),并且发现它被该变元使用阻挡元对象1103所阻挡。它把在“链接A”中的正向指针1111内的x02迭代变元等待(iterating_mutator_waiting)标志设置开启,以表示(一个或多个)迭代变元正在等待。最后,它把curLink 1115设置为指向阻挡元对象1103,把x01承诺等待者和x04优先级不冲突标志设置开启,以表示它承诺等待该变元使用阻挡元对象1103来解阻挡“链接A”中的正向链接指针1111,并且确定它不需要与变元的任务优先级任务相冲突。
4.最后,使用阻挡元对象1104的变元也要阻挡“链接A”内的正向链接指针1111,但是发现它已经被使用阻挡元1103的变元所阻挡。把“链接A”内的正向链接指针1111中的x04阻挡变元等待标志设置开启,以表示(一个或多个)阻挡变元正在等待。最后它把其阻挡元对象1104内的等待阻挡元字段1116设置为指向阻挡元对象1103,并且把x01承诺等待者和x02优先级冲突标志设置开启,以表示它已经承诺等待使用阻挡元1103的变元解阻挡其链接指针,并且它已经与变元的任务优先级相冲突。
图11表示在执行上述步骤之后的指针状态。然后,当使用观察对象1101的变元已经处理完成其当前链接,并且前进到下一个链接,它将看到x01承诺等待者和x02优先级冲突标志,并且将把它现在已经前进的情况通知给使用阻挡元1103的变元(其阻挡在“链接A”内的正向链接指针),并且将解决其自身任务优先级的冲突。然后,该变元将唤醒并且结束插入新的链接,并且将最终解阻挡其链接指针。然后,它将看到存在正在等待的迭代和阻挡变元(在受阻的正向链接指针1111中的x02迭代变元等待和x04阻挡元等待标志开启),并且将在SharedChain对象中的列表查找它们的观察和阻挡元对象。它将把一个新的当前链接给予观察对象1102(当它解阻挡它时,把其curLink1115设置为它已经置于“链接A”内的正向链接指针1111中的相同数值)并且唤醒其变元。它还将把阻挡元对象1104中的等待阻挡元(waiting-for-bolcker)字段1116设置为NULL,并且唤醒其变元,然后该变元可以再次尝试阻挡该链接指针。同时,使用阻挡元对象1103的变元将解决其自身任务优先级的冲突,以恢复从使用阻挡元对象1104的变元接收优先级冲突。SharedChain对象除了指向链中的第一和最后链接的指针之外,SharedChain对象具有多个如下包含状态信息的字段无效链接指针(inactive link pointer)该字段包含NULL,并且排列在一个8字节边界上。当一个观察对象无效时,其curPtr705字段包含该字段的地址,并且curLink706为NULL。按照这种方式,对于无效观察对象没有任何特别之处。看到它的任何阻挡变元将立即忽略它,因为在curPtr705中的唯一数值从来不匹配该变元所感兴趣的任何正向链接指针的地址,从而这是保持观察对象脱离阻挡变元的路而不把它当作一种特殊情况的常规方法。
主要和次要阻挡元列表头(primary and secondary blocker listhead)这些字段指向阻挡元对象的列表中的第一阻挡元对象。在任何时刻,仅仅这些字段中的一个为有效。阻挡元对象的列表是单链接表。当新的阻挡元对象产生时,使用compareAndSwap()函数来原子地在该列表的头部插入新的阻挡元对象。但是,在以后删除不需要的阻挡元对象不能够用对链开头的单个原子更新来完成,这还保证阻挡元对象仍然是不必要的;而是将需要对表示链头为有效的标识符的单原子更新。
主要和次要检查元观察列表头(primary and secondary inspectorview list head)这些字段是指向用于检查元的观察对象的列表中的第一观察对象的指针。这些字段被按照主要阻挡元列表头和次要阻挡元列表头字段被管理的相同方式来管理。
主要和次要变元观察列表头(primary and secondary mutatorview list head)这些字段是指向用于变元的观察对象的列表中的第一观察对象的指针。这些字段被按照主要阻挡元列表头和次要阻挡元列表头字段被管理的相同方式来管理。
有效阻挡元和观察计数(Activated blocker and view counts)该字段包含用作为当前有效的阻挡元和观察对象的数目的两个分离计数器的单个整数,高阶数位被用作为用于有效阻挡元对象的数目的计数器,并且低阶数位被用作为用于有效观察对象(检查元和变元的总和)的数目的计数器。两个部分被作为单个原子字段而更新。在阻挡元对象被分配给变元之前,该阻挡元部分被增加1,并且在不再有任何由其它阻挡元或观察对象对该阻挡元对象的剩余引用之后,该阻挡元部分被减1。在观察对象被分配给一个迭代器(一个检查元或变元)之前,该观察部分被增加1,并且在该迭代器被复位之后,它被减1。每个部分的最高阶数位不被用作为该计数值的一部分,而是被保留。这些保留数位中的一个被运作为表示reclaim()函数正在进行的标志(reclaim(回收利用)是删除不需要的阻挡元和/或观察对象的过程)。该过程仅仅当整个字段为0时开始(没有有效的阻挡元和观察对象,并且还没有进行回收利用)。
阻挡元和观察存在计数(blocker and view existence counts)该字段包含作为当前存在的阻挡元和观察对象的数目的两个分离计数器的单个整数,高阶数位被用作为用于现有阻挡元对象的数目的计数器,并且低阶数位被用作为用于现有观察对象(检查元和变元的总和)的数目的计数器。两个部分被作为单个原子字段而更新。当一个新的阻挡元对象必须产生时(在增加该有效阻挡元和观察计数字段的阻挡元部分之后,但是在产生该阻挡元对象并把它添加到列表的开头之前),该阻挡元部分被增加1。当新的观察对象必须产生时(在增加该有效阻挡元和观察计数字段的观察部分之后,但是在产生该观察对象并把它添加到适当列表的开头之前),该观察部分被增加1。两个部分仅仅由reclaim()函数减小。每个部分的最高阶数位不被用作为该计数值的一部分,而是被用作为一个标志。在阻挡元部分中的标志表示该主要阻挡元列表头或者次要阻挡元列表头为有效。在观察部分中的标志表示该主要观察存在技术或者该次要观察存在计数字段(在下文中描述)为有效。该标志按照需要被reclaim()函数所切换(toggled)。该有效阻挡元和观察计数字段以及阻挡元和观察存在计数字段不能被作为单个原子字段一同更新。但是,它们位于相同的4字节长字中,从而它们可以独立地由compareAndSwapQualified()函数所更新,如果同时任何字段被改变,则该函数失败。
主要和次要观察存在计数(primary and secondary view existencecounts)在同一时刻仅仅这些字段中的一个有效。由上述的该阻挡元和观察存在计数字段的观察部分中的标志表示哪个字段有效。每个字段包含一个整数,用作两个独立的计数器。每个字段的高阶数位被用作为检查元的现有观察对象的数目的计数器,并且每个字段的低阶数位被用作为用于变元的现有观察对象的数目的计数器。两个部分都被作为单个原子字段而更新。当必须产生一个新的观察对象时,适当的计数器(用于检查元或者用于变元)被增加1(在增加阻挡元和观察存在计数字段中的总计数之后以及在产生观察对象并且把它添加到适当列表的开头之后)。两个部分都仅仅由reclaim()函数所减小。每个部分的最高阶数位不被用作为该计数值的一部分,而被用作为一个标志。在检查元部分中的标志表示该主要检查元观察列表头或者次要检查元观察列表头字段为有效。在变元部分中的标志表示该主要变元观察列表头或者次要变元观察列表头为有效。该标志按照需要由reclaim()函数所切换(toggled)。
有效检查元观察计数(active inspector view count)该原子字段包含用于非原子检查元的有效观察对象的数目的计数值。在用于一个检查元的观察字段被从无效状态转移到该链中的一个链接之前,该字段被增加1,并且在观察对象被从该链中的一个链接转移回无效状态之后,该字段被减小1。该字段的目的是减小变元与观察对象的列表交互作用的次数当一个变元阻挡一个链接指针并且需要为检查元查看观察对象时,如果该字段不为0,它仅仅需要做此操作。仅仅当为了相同的观察对象使得有效阻挡元和观察计数字段的观察对象部分已经增加之后,并且为了同一观察对象使它被减小之前,该字段才能够为了特定的观察对象而被增加或减小。
有效变元观察计数(active mutator view count)该原子字段包含用于非原子变元的有效观察对象的数目的计数值。该字段在一个用于变元的观察对象被从无效状态转移到链中的一个链接之前被增加1,并且在该观察对象从链中的一个链接转移到无效状态之后减小1。该字段的目的是减小变元必须与观察对象的列表交互作用的次数当一个变元阻挡一个链接指针并且需要查看用于变元的观察对象时,如果该字段非零,它仅仅需要作此操作。仅仅在有效阻挡元和观察计数字段的观察对象部分已经为相同的观察而增加之后,以及在它为相同观察对象减小之前,该字段仅仅可以为特定的观察对象增加或减小。迭代在该优选实施例的情况中,在观察对象内的curLink706和curPtr705字段不能作为单个字段而自动更新。由于它们必须在一次更新一个,并且阻挡变元可以在任何时候观察这些字段,因此所有更新必须按照这样一种方式完成,使得观察对象状态可以被在每次可能的curLink和curPtr的快照观察中准确地掌握。两个字段在相同的4字节长字中,使得如果同时更新任何一个字段,要更新其中一个字段的compareAndSwapQualified()函数将会失败。在无效状态中的非原子迭代器当非原子迭代器(检查元或变元)处于无效状态时,它没有观察对象。当前与一个迭代器无关的所有观察对象被认为是无效的。无效观察对象具有指向SharedChain对象中的无效链接指针字段的curPtr705,以及设置为NULL的curLink。
在改变函数过程中,属于一个变元的观察对象也(通常)无效。其curLink706和curPtr705字段被设置如上,并且有效检查元观察计数字段或者有效变元观察计数字段(适当的)不增加。把非原子迭代器(检查元或变元)前进到链中的第一链接当该处理开始时,该迭代器假设处于无效状态。完成它的步骤如下1.取消占先(Disable preempt)。
2.把有效阻挡元和观察计数字段的观察部分增加1。在适当的列表中查找可用的观察对象。如果没有可用观察对象,则增加阻挡元和观察存在计数字段的观察部分,创建一个新的观察对象,把其添加到适当的列表开头,并且增加主要观察存在计数或次要观察存在计数字段(无论哪一个有效)的检查元或变元部分(作为适当的)。
3.把有效检查元观察计数或有效变元观察计数字段(作为适当的)增加1。
4.把观察对象的curLink字段706设置为特殊的过渡数值(000...002)。由于在此时,curPtr字段705指向SharedChain对象内的无效链接指针字段,因此没有变元将对观察对象感兴趣。但是,这将在下一步骤中变得重要,并且也必须被首先设置。
5.把观察对象的curPtr字段705变为指向SharedChain对象内的第一链接指针字段。任何阻挡或解阻挡该链接指针的变元现在将对该观察对象感兴趣。在curLink706中的特定过渡数值把迭代器要用它通过解除引用curPtr而获得的数值设置curLink的情况告诉变元。该变元不知道是否已经出现解除引用的情况,如果已经出现,则它不知道在阻挡或解阻挡链接指针(无论它做何操作)的变元之前还是之后出现。因此,该变元将不知道迭代器将把哪个数值设置在curLink中。为了避免这种情况,变元将尝试把curLink改变为特殊的错误比较数值(miscompare)(00...04)。如果该变元成功,则迭代器将在尝试设置它解除从curPtr到curLink的引用的时间中失败,并且将再次解除引用curPtr。按照这种方式,变元可以确保迭代器看到它对链接指针所做的改变。
6.移到链中的第一链接是从一个链接前进到下一个链接的更加一般处理的一种特殊情况。在这一点,前端(front-end)特殊情况步骤被完成,并且该处理可以用更加一般的处理继续执行。如果在此有一个检查元,处理可以继续到下文中所述的把非原子检查元前进到下一个链接的步骤3继续。
(把一个迭代器移动到任意链接之后的链接的操作是类似的。在上述步骤5中,替代把curPtr设置为指向SharedChain对象内的第一链接指针,它被设置为指向任意链接内的正向链接指针。)把非原子检查元前进到下一个链接当一个变元具有在其观察对象中的一个当前链接时,该curLink字段指向该链接,并且curPtr字段指向当前链接内的正向指针。为了前进,两个字段将到达相同的相对位置,但是相对于该链中的下一个链接。由curPtr所定位的正向链接指针当前可能被或可能不被阻挡。采取如下步骤1.取消占先。
2.把curLink设置为特殊的过渡数值。任何阻挡或不阻挡curPtr所指向的链接指针的变元如果看到该数值后将知道检查元要用它通过解除引用curPtr而获得的数值设置curLink。该变元无法知道是否已经出现解除引用,如果已经出现,则它不知道在阻挡或解阻挡链接指针(无论它做何操作)的变元之前还是之后出现。因此,该变元将不知道迭代器将把哪个数值设置在curLink中。为了避免这种情况,变元将尝试把curLink改变为特殊的错误比较数值。如果该变元成功,检查元将在步骤8设置curLink时失败,并且将再次解除引用curPtr。按照这种方式,变元可以确保检查元看到变元对链接指针所做的改变。
3.解除引用curPtr以获得该链接指针的内容。如果它不被阻挡,则转到步骤8;否则继续进行到步骤4。
4.该链接指针被阻挡并且包含指向属于阻挡它的变元的阻挡元对象的指针。从阻挡元中获得有效标识(activation_id),并且保存它用于可能的以后使用。如果该链接指针被要删除包含被阻挡的链接指针的链接的变元所阻挡,则获得次要的下一个链接(secordary_next_link)字段,并且把它保存作为下一个链接指针,用于可能的以后使用;否则获得主要的下一个链接(primary_next_link)字段并且保存它。
5.再次解除引用curPtr。如果该链接指针不被阻挡,则转到步骤8。
6.该链接指针或者仍然被阻挡,或者已经被再次阻挡。从该阻挡原对象获得有效标识字段。如果该有效标识与以前获得的不同,则该链接指针被再次阻挡。在这种情况下,回到步骤4。
7.该有效标识是相同的,意味着在步骤4中提取的主要的下一个链接或者次要的下一个链接字段是指向下一个链接的指针。(请注意在此时,阻挡链接指针的变元现在可能已经解阻挡它了。当解阻挡时,置于链接指针中的数值将于从主要的下一个链接或者次要的下一个链接字段中提取的相同,并且在这种情况下,所提取字段仍然有效。但是,如果在该变元解阻挡链接指针之后,它被用另一个阻挡元的行为再次阻挡,所提取数值可能不再是正确的。但是,在使用另一个阻挡元的变元可以解阻挡其链接指针之前,它将查找必须交互作用的观察对象,并且将看到带有定位被论讨的链接指针的curPtr的这个对象。首先根据该变元或检查元是否在设置curLink中成功,变元或者等待使用该观察对象来前进的检查元,或者它将把curLink改变为特殊的错误比较数值,以使得检查元在步骤8中设置curLink的尝试失败。)8.使用compareAndSwap()函数来尝试把下一个链接指针设置到curLink。这将是检查元的新的当前链接,并且将是在步骤3或步骤5中从curPtr解除引用的数值,或者是在步骤4从主要的下一个链接或者次要的下一个链接字段中提取的数值。如果compareAndSwap()函数失败,则它仅仅因为一些变元把curLink从所期望的过渡数值改变为错误比较数值。如果它失败的话,则返回步骤2继续进行。
9.如果新的当前链接是NULL,它表示该链的末端已经到达。在这种情况下,继续执行在把非原子迭代器(检查元或变元)设置为无效状态中的步骤2。
10.如果新的当前链接不是NULL,则新的当前链接已经被建立。现在使用compareAndSwap()来尝试改变curPtr,以定位在新的当前链接中的指针,同时确认curPtr的旧数值。如果curPtr的旧数值具有x04删除等待标志开启,则还包括在被设置的curPtr的新数值中的x01承诺等待者和x02优先级冲突标志如其所设。如果尝试失败,则该步骤被重复直到成功为止。
11.如果在步骤10中获得的curPtr的旧数值没有使得x01承诺等待者标志开启,则没有等待该检查元前进的变元。在这种情况下,转到步骤19;否则继续执行步骤12。
12.在curPtr的旧数值中,x01承诺等待者标志为开启,从而变元在等待前进的通知。如果x04删除等待标志也为开启,则前进的通知需要被推迟到下一次前进。在这种情况下,转到步骤17;否则继续执行步骤13。
13.x04删除等待标志为关闭,从而变元需要在此时被通知。curPtr的旧数值指向该变元已经阻挡的链接指针,从而从该链接指针获得指向变元的阻挡元对象的指针,并且通知它前进。
14.如果在curPtr的旧数值中x02优先级冲突标志为开启,则等待变元表明它已经与检查元的任务优先级冲突。在这种情况下,转到步骤16;否则继续执行步骤15。
15.在curPtr的旧数值中,x02优先级冲突标志为关闭,这意味着在等待变元有机会表明它已经与检查元的任务优先级冲突之前,检查元改变了curPtr。为了保证检查元在变元能够与它冲突之前不解除冲突其自身的任务优先级,等待在观察对象内的优先级冲突不确定解决器(rpiority_bump_uncertainty_resolver)(单任务阻挡元对象)。(当变元尝试把curPtr中的x02优先级冲突标志设置开始时,并且看到curPtr已经改变,则它将解阻挡观察对象的优先级冲突不确定解决器)。当等待中的检查元苏醒时,它可以保证其任务优先级已经被冲突。
16.解除冲突(unbump)该检查元的任务优先级。转到步骤19继续执行。
17.在这一点,有要被通知的等待中的变元,但是在curPtr的旧数值中的x04删除等待标志为开启,从而通知退迟到下一个前进过程中。(该标志被设置为在步骤10中完成该操作)。如果在curPtr的旧数值中x02优先级冲突(priority_bumped)标志也为开启,则等待中的变元已经表明它已经冲突检查元的任务优先级。在这种情况下转到步骤19;否则,继续执行步骤18。
18.在curPtr的旧数值中,x02优先级冲突标志为关闭,这意味着在等待变元有机会表明它已经与检查元的优先级相冲突之前,检查元改变了curPtr。为了保证检查元在变元能够冲突之前不解除冲突(unbump)自身任务优先级,等待在观察对象内的优先级冲突不确定解决器(单任务阻挡元对象)。(当变元尝试把curPtr内的x02优先级冲突标志设置开启并且看到curPtr已经改变时,它将解阻挡观察对象的优先级冲突不确定解决器)。当等待中的检查元苏醒时,它可以确保其任务优先级已经被冲突。(当它下一次前进时,它将看到在此时将为curPtr的旧数值中的x02优先级冲突标志(在步骤10中设置开启)并且将得知解除冲突其任务优先级)。
19.在这一点,前进完成,并且占先被允许。把非原子变元前进到下一个链接一个变元具有一个当前链接,则在其观察对象内,curLink字段指向该链接,并且curPtr字段指向前一列接内的正向指针。为了前进,两个字段将到达相同的相对位置,但是一个链接进一步沿着该链。由curPtr所定位的正向链接指针当前可能被阻挡或不被阻挡。(除了由非原子变元所使用之外,当检查元复位到无效状态时,该代码路径还由非原子检查元所使用。但是,当复位到无效状态时,检查元将不会遇到一个被阻挡的链接指针。通过此处可以由检查元或变元所使用的路径被针对迭代器而描述;仅仅应用到变元的路径被针对迭代变元而描述。)1.禁止占先。仅仅对于getNextLink()函数,该处理在该步骤(步骤1)开始;所有其它情况进入到随后的步骤。
2.使用compareAndSwap()函数尝试改变curPtr,以在现有当前链接中定位正向指针,同时确认curPtr的旧数值。如果curPtr的旧数值使得x04删除等待标志开启,并且为getNextLink()函数调用这个代码路径,则在curPtr的新数值中还包括被设置的x01承诺等待者和x02优先级冲突标志如其所设。由于一个阻挡变元可能是在设置curPtr中的标志,重复该步骤,直到它成功。(如果不是因为getNextLink()函数,则任何迭代器前进的所需通知必须不被推迟,直到一个后来的前进)。
3.把curLink设置为特殊的过渡数值。阻挡或解阻挡curPtr所指向的链接指针的任何阻挡变元,参见在curLink中的数值,将得知该迭代器要用通过解除引用curPtr而获得的数值来设置curLink。该阻挡变元无法得知解除引用是否已经发生,如果它已经发生,则不知道它是在阻挡或解阻挡链接指针之前还是之后发生(无论它做何操作)。因此,阻挡变元将不知道迭代器将把什么数值设置在curLink中。因此,阻挡变元将尝试把curLink改变为特殊的错误比较值。如果阻挡变元成功,则迭代器将不能在步骤6中设置curLink,并且将重新开始并再次解除引用curPtr。按照这种方式,阻挡变元可以保证迭代器将看到阻挡变元对链接指针所作的改变。
4.解除引用curPtr以获得链接指针的内容。如果它没有被阻挡,则转到步骤6。否则,如果它被要删除包含受阻挡链接指针(x08删除未决标志开启以及x04阻挡变元等待标志关闭)的链接的变元所阻挡,则转到步骤5。否则该链接指针被阻挡,但是包含它的链接不被当前已经阻挡它的变元所删除。如果x02迭代变元等待(iterating_mutator_waiting)标志在受阻挡链接指针中已经开启,则转到步骤6继续执行。否则x02迭代变元等待标志在受阻挡链接指针中不是开启的,从而使用compareAndSwap()函数来尝试把它设置为开启。如果它失败,回到步骤3并且重新开始。否则,如果成功设置开启,则当阻挡变元解阻挡其链接指针时,它将看到该标志并且知道查看变元观察对象以唤醒任何等待者。转到步骤6继续执行。
5.在这一点,连接指针被要删除受阻挡链接指针的链接的变元所阻挡。在阻挡链接指针时,该阻挡变元存储指向在其阻挡元对象中的次要的下一个链接指针字段内的下一个链接的指针,从而提取现在要被用作为下一个链接指针的数值。(阻挡变元将(最终)等待该迭代变元前进,从而安全地从其阻挡元对象内获取下一个链接指针)。
6.使用compareAndSwap()函数来尝试把curLink从所期望的过渡数值改变为在步骤4中从curPtr解除引用的数值(或者在步骤5中从阻挡元对象检索的数值)。(但是,如果链接指针被阻挡(x01受阻挡链接指针标志开启),要被存储的数值是指向阻挡元对象的指针,从而当存储到curLink中时,除了x01之外把所有标志设置为关闭。在curLink中的x01标志是承诺等待者标志,表示迭代变元现在已经承诺等待阻挡变元来解阻挡其链接指针。)如果该尝试失败(由于在同时一个变元已经把curLink改变为特殊的错误比较数值)则转回到步骤3重新开始。
7.在这一点,迭代器已经成功离开其旧的当前链接。如果x01承诺等待者标志在curPtr的旧数值中不为开启(从步骤2),则没有阻挡变元等待被通知该变元前进的情况。在这种情况下,转到步骤15;否则,继续执行步骤8。
8.阻挡变元等待前进的通知。如果x04删除等待标志为开启,并且该过程作为getNextLink()函数的一部分而执行,则前进的通知被推迟直到下一次前进。在这种情况下,转到步骤13;否则,继续执行步骤9。
9.x04删除等待标志为关闭(或者迭代变元不处理getNextLink()函数),从而等待变元在此时被通知。curPtr的旧数值指向该变元已经阻挡的链接指针,从而从该链接指针获得指向变元的阻挡元对象的一个指针,并且通知它前进的情况。
10.如果x02优先级冲突标志在curPtr的旧数值中为开启,则等待变元已经表明与迭代器的任务优先级相冲突。在这种情况下,转到步骤12;否则,继续执行步骤11。
11.x02优先级冲突标志在curPtr的旧数值中为关闭,这意味着迭代器在等待变元有机会表明它已经与迭代器的任务优先级相冲突之前,迭代器改变了curPtr。为了保证迭代器在等待变元能够冲突它之前不解除冲突其任务优先级,等待在观察对象内的优先级冲突不确定解决器(单个任务阻挡元对象)。(当该变元尝试把curPtr中的x02优先级冲突标志设置为开启时,并且看到curPtr已经改变,它将解除冲突该观察对象的优先级冲突不确定解决器)。当等待迭代器苏醒时,它可以肯定其任务优先级已经冲突。
12.解除冲突(unbump)迭代器的任务优先级。转到步骤15继续执行。
13.在这一点,有一个等待变元要被通知,但是该通知将被推迟,直到下一次前进时为止。(该标志被设置以在步骤2中完成该操作)。如果x02优先级冲突标志在curPtr的旧数值中为开启,则等待变元已经表明它已冲突迭代器的任务优先级。在这种情况下,转到步骤15(当下一次前进时,该迭代器将通知x02优先级冲突标志);否则,继续执行步骤14。
14.x02优先级冲突标志在curPtr的旧数值中为关闭,这意味着迭代器在等待变元有机会表明它已经冲突迭代器的任务优先级之前改变curPtr。为了确保迭代器在变元能够冲突它时不解除冲突其任务优先级,等待在观察对象内的优先级冲突不确定解决器(单个任务阻挡元对象)。(当变元尝试设置在curPtr中的x02优先级冲突标志开启,并且看到curPtr已经改变时,它将解除冲突该观察对象的优先级冲突不确定解决器)。当等待迭代器苏醒时它可以确定其任务优先级已经被冲突。(当它下一次前进时,它将在此时看到将为curPtr的旧数值的x02优先级冲突标志(在步骤2中设置为开启)并且将知道解除冲突其任务优先级)15.如果在步骤6中存储到curLink中的数值不是指向阻挡元对象的指针(x01承诺等待者标志关闭),则迭代器完成其前进过程。在这种情况下,转到步骤17;否则,继续执行步骤16。
16.迭代变元已经承诺等待阻挡元地址被存储在curLink中的变元,来解决冲突由curPtr所定位的链接指针。在下文中的等待和唤醒等待一个变元解阻挡其链接指针的处理步骤,以尝试冲突该阻挡变元的任务的优先级,并且等待它解阻挡该链接指针。当阻挡变元解阻挡其链接指针时,它将把它置于(未阻挡)正向指针中的相同数值设置到curLink,并且唤醒该迭代变元。当唤醒时,该迭代变元将完成其前进过程。
17.允许占先。把非原子迭代器(检查元或变无)复位为无效状态当由客户所请求(或者当其解除程序运行时),一个迭代器将被复位到无效状态(其观察对象也被无效并且可以重新使用)。另外,当前进到链的末端时,一个检查元将被复位到无效状态。最后,当变元开始一个改变函数时(当改变函数完成时,观察对象可以返回到有效状态),用于一个变元的观察对象将复位到无效状态(但是将仍然与该变元相关)。其处理步骤如下1.禁止占先。
2.执行上述把非原子变元进行到下一个链接的处理步骤,以步骤2为开始,但是在步骤2中,curPtr被设置为在SharedChain对象内的无效链接指针(inactive_link_pointer)字段的地址(而不是设置为在当前链接中的正向指针的地址)。这将把观察对象移动“离开该链”,使得在以后没有阻挡元对象对它感兴趣。(由于有效链接指针字段包括NULL,则当它被在步骤4中解除引用时,它将不会表现为被阻挡。因此将没有等待被解阻挡的链接指针,尽管当迭代器前进离开其当前链接时阻挡变元可能需要被通知)。
3.把在(适当的)SharedChain对象中的有效检查元观察计数或者有效变元观察计数字段减1。
4.如果仅仅是观察对象被复位(并且迭代器本身保持在有效或过渡状态),则该处理被完成;否则执行步骤5。
5.观察对象可以由另一个迭代器重新使用。把在SharedChain对象中的有效阻挡元和观察计数(activated_blocker_and_view counts)字段的观察部分减1。如果整个字段现在为0,这意味着不再有对任何观察对象或者阻挡元对象的任何突出引用,从而调用reclaim函数,以删除任何过量的观察或阻挡元对象。为非原子变元建立或重新建立一个新的当前链接除了insertAfterCurrentLink()和removeAfterCurrentLink()函数之外,当一个变元插入或删除一个链接时,它没有一个观察对象,或者它的观察对象已经被复位到无效状态。当该函数接近完成时,但是链接指针还没有被解阻挡,则该变元的当前链接可以被建立或重新建立,如下1.如果变元已经具有一个观察对象,则转到步骤2。否则,作如下操作以分配一个观察对象(a)把在SharedChain对象中的有效阻挡元或观察计数(activated_blocker_and_view_counts)字段的观察部分增加1;(b)在变元观察对象列表中查找一个可用的观察对象。如果没有可用的观察对象,则把阻挡元和观察存在(blocker_and_view_existance_counts)计数字段的观察部分增加1.创建新的观察对象,把它添加到变元观察对象列表的开头(使用有效的主要或次要头),并且把主要观察存在计数或者次要观察存在计数字段(无论哪个有效)的变元部分增加1。
2.把在SharedChain对象中的有效变元观察计数字段增加1。
3.在这一点,观察对象的curLink字段为NULL,并且其curPtr字段在SharedChain对象中定位无效链接指针(inactive_link_pointer)字段。该观察对象与可能查看它的任何变元无利害关系。
4.把curLink改变为指向链接,该链接当以后被解阻挡时将被在以前链接中的正向链接指针所指向。如果插入一个链接,这将是新插入的链接;如果删除一个链接,则它将是跟随在它后面的链接。由于curPtr从前一步骤开始保持不变,则该观察对象仍然与任何变元无关。
5.把curPtr改变为指向前一链接内的正向链接指针。在这一点,观察对象具有新的当前链接,并且与任何其它用于一个迭代变元的任何其它观察对象没有不同,在该链接指针不被解阻挡之后,该迭代变元将前进到该链接。改变非原子变元的当前链接当非原子变元在任何与当前链接相关的改变函数中失败时,这是因为一个第二个变元已经阻挡受影响的链接指针。第二变元将不知道第一变元的意图,并且将仅仅把第一变元看作为一个迭代变元,并且将等待它前进。第一变元将必须作为一个迭代变元,并且离开第二变元的路径,然后将等待它解阻挡链接指针。在等待之后根据情况,该变元将具有或不具有一个新的当前链接。如果它具有新的当前链接,则原始函数将失败,因为它基于原始当前链接;如果没有,则该函数可能被重试。原始删除或插入函数必然失败,因为它基于原始链接指针。表14描述该函数、失败的原因、以及恢复。
表14失败的原因以及补救
向后移动一个受阻挡链接指针1.如果x02迭代变元等待标志在向后移动的受阻挡链接指针中不为开启,则使用compareAndSwap()函数来尝试把它设置为开启。如果失败,则重新尝试直到该标志被开启为止。由于第一变元在第二变元的路径上,第二变元将不能够解阻挡该链接指针,直到第一变元前进离开其路径时为止,从而compareAndSwap()函数可以简单地被重新尝试直到它成功。
2.把第一变元的观察对象内的curLink字段改变为指向第二变元的阻挡元对象(x01承诺等待者标志开启)。这表明第一变元已经承诺等待第二变元解阻挡其链接指针。
3.如果x01承诺等待者标志在curPtr字段中为开启,则使用compareAndSwap()函数来尝试把所有标志位(x07)设置为关闭,并且知道哪一个为开启。如果该尝试不成功(由于第二变元把x02优先级冲突标志设置为开启),该步骤被重新尝试直到成功。(如果x01承诺等待者标志不为开启,则第二变元将不把它设置为开启,因为在步骤2中的改变使得第一变元表现为承诺等待第二变元。在在这种情况中,第二变元不承诺等待第一变元。即使第二变元在承诺等待的过程中,在步骤2中的curLink的设置将失败,并且当重新尝试时,取而代之的是第二变元将注意到第一变元已经承诺等待它开启。)4.如果在步骤3中发现x01承诺等待者标志在curPtr的旧数值中为开启,它表明第二变元已经承诺等待第一变元前进,从而现在是把前进的情况通知给它的时候。(第二变元还把x02优先级冲突标志以及x04删除等待标志设置为开启;但是,x04删除等待标志被忽略,因为前进的通知将不被推迟。
5.等待第二变元解阻挡其链接指针。下文等待变元解阻挡其链接指针的处理步骤被执行以尝试冲突第二变元的任务的优先级,并且等待它解阻挡该链接指针。当第二变元解阻挡其链接指针时,它将看到第一变元的观察对象,并且将用新的链接指针设置它的curLink字段,并且唤醒第一变元。当唤醒时,第一变元将具有其新的当前链接。阻挡一个链接指针阻挡一个链接指针而不等待该函数被用于尝试阻挡在前一链接中的正向指针,采用如下函数
insertBeforeCurrentLink()removeCurrentLink()insertBeforeArbitraryLink()在尝试性地阻挡在任意链接中的反向指针之后removeArbitraryLink()在尝试性地阻挡在任意链接中的反向指针之后insertLast()在尝试性地阻挡在SharedChain对象内的最后链接指针之后。
它还由另一个用等待/重试逻辑包装它的阻挡函数内部使用。涉及在阻挡一个链接指针的步骤被在此详细描述。本质上,链接指针的旧数值被交换出去,并且返回到调用者,并且新的数值(指向具有标志位组的阻挡元对象)被交换进来,只要该链接指针还没有被阻挡即可。
1.解除引用该链接指针以得到其当前内容。如果它被另一个变元所阻挡,则退出,返回链接指针的当前内容(一个指针指向阻挡变元的阻挡元对象),以表明失败;否则继续。
2.如果阻挡一个正向链接指针,但是不在被删除的链接内,把链接指针的当前内容(在步骤1中获得)存储到主要的下一链接(primary_next_link)字段。如果阻挡在被删除中的链接内的正向指针,把链接指针的当前内容存储到次要的下一个链接字段。(否则,如果阻挡一个反向链接指针,则没有任何东西被存储在阻挡元对象中)。
3.当知道链接指针的当前内容时如果可以完成该操作,使用compareAndSwap()来尝试把链接指针改变为指向阻挡元对象(适当的标志被设置为开启)。如果该操作失败,则返回到步骤1重新开始。
4.如果刚刚被阻挡的链接指针为在正在被删除的一个链接内的正向链接指针,则把次要的下一个链接字段复制到主要的下一个链接字段。
5.退出,返回链接指针的原始内容(在步骤1中获得)。指向一个链接而不是指向一个阻挡元对象的事实表明在此尝试的阻挡操作已经成功。阻挡一个链接指针并等待当尝试性的阻挡用于如下函数的反向指针时使用该函数insertLast()insertBeforeArbitraryLink()removeArbitraryLink()它还被用于阻挡在用于如下函数的前一链接中的正向指针insertFirst()insertAfterCurrentLink()insertAfterArbitraryLink()removeFirst()removeAfterArbitraryLink()
在阻挡元对象中的等待阻挡元字段被首先初始化为NULL,以表明该变元不在等待。
1.调用上述阻挡一个链接指针而不等待中的过程来试图阻挡该链接指针。如果成功,则退出,返回链接指针的原始(解阻挡的)内容;否则继续执行步骤2。
2.阻挡尝试已经失败,因为该链接指针已经被另一个变元所阻挡,并且指向其它变元的阻挡元对象的一个指针被失败的尝试所返回。把一个指向该第二阻挡元对象(所有标志为被设置为关闭)的指针存储到在第一阻挡元对象中的等待阻挡元(waiting_for_blocker)字段。没有标志位开启的事实表明第一变元要等待第二变元,但是还没有承诺等待。
3.解除引用要被再次阻挡的链接指针。如果它仍然没有被相同的变元所阻挡,则返回到步骤1重新开始。(在返回到步骤1中,等待阻挡元字段被置于其中间状态,但是不会产生有害的影响。当解阻挡链接指针时,使用所指向的阻挡元对象的变元可能后来把该字段复位为NULL,但是当把它设置为NULL时,由于没有标志被设置,因此它将不采取进一步的行动。)4.如果x04阻挡变元等待(blocking_mutator_waiting)标志在受阻挡链接指针中不为开启,则使用compareAndSwap()尝试把它设置为开启。如果该操作失败,则返回到步骤1重新开始。
5.使用compareAndSwap()尝试把在等待阻挡元字段中的x01承诺等待者标志设置开启,以表明第一变元现在没有承诺等待第二变元解阻挡其链接指针。如果尝试失败,因为第二变元已经解阻挡链接指针,并且把等待阻挡元对象复位为NULL。在这种情况下,返回到步骤1重新开始。
6.在这一点,第一变元已经承诺等待第二变元。执行在等待一个变元解阻挡其链接指针中的步骤,以尝试冲突第二变元的任务的优先级,并且等待它解阻挡链接指针。当被唤醒时,返回到步骤1重新开始。有条件地阻挡正向链接指针当在当前链接之后插入或删除时,该函数被用于尝试阻挡在当前链接中的正向指针。
1.调用上述阻挡一个链接指针而不等待,以尝试阻挡该链接指针。如果成功,则退出,返回该链接指针的原始(未阻挡)的内容,以表明成功;否则继续执行步骤2。
2.阻挡尝试失败,并且返回该链接指针的受阻挡内容。如果该链接指针被正在删除包含受阻挡指针的链接的变元所阻挡(x08删除未决(remove_pending)标志开启以及x04阻挡变元等待标志关闭),则退出,返回链接指针的原始(受阻挡)内容,以表明失败;否则,继续执行步骤3。
3.该链接指针被不要删除包含它的链接的第二变元所阻挡。执行在上述阻挡一个链接指针并等待中所述的步骤,以等待该链接指针被解阻挡。如果任何这些步骤失败,或者当从等待中苏醒时,返回到步骤1重新开始。在尝试性地阻挡一个反向链接指针之后,阻挡一个正向链接指针当删除一个任意链接时,或者当在一个任意链接之后或之前插入时,该函数被用于阻挡在前一链接中的正向指针。反向指针已经被用尝试性标志所阻挡。
1.调用上述阻挡一个链接指针而不等待中的过程,以尝试阻挡该链接指针。如果成功,转到步骤4;否则,继续执行步骤2。
2.阻挡尝试失败,并且它把一个指针返回到用于阻挡已经阻挡该链接指针的变元的阻挡元对象。第二变元还将阻挡第一变元以前已经尝试性阻挡的同一链接指针,并且为避免死锁,尝试性阻挡被暂停,从而第二变元可以使用它。为了暂停该尝试性阻挡,具有在第二变元的阻挡元对象中的暂停连接控制(susperded_link_control)对象的链接传送机制被用于把指向该链接的一个指针传送到第二变元,在该链接被阻挡之前,该链接被尝试性阻挡的反向指针所指向。
3.在失败变元的阻挡元对象中,与暂停链接控制对象一起使用链接传送机制,以等待第二变元返回一个指向新的前一链接的指针。然后返回到步骤1重新开始,尝试阻挡在该新的前一链接中的正向指针。
4.在这一点,正向链接指针已经被成功地阻挡,并且被尝试性阻挡的反向链接指针不再需要是尝试性的。使用compareAndSwap()来试图把其中的x08尝试标志设置为关闭。如果该函数失败,则重复执行它直到成功为止。(另一个变元可能正在设置在此处的x04阻挡变元等待标志)。
5.退出该过程,返回该链接指针的原始(解阻挡的)内容。阻挡在被删除的链接中的正向链接指针1.上述阻挡链接指针而不等待的过程被调用以尝试阻挡该链接指针。如果成功,则退出,返回该链接指针的原始(未阻挡)内容;否则,继续该过程到步骤2。
2.阻挡尝试失败,因为第二变元已经阻挡该链接指针。CompareAndSwap()被用于尝试把在受阻挡链接指针中的x08删除未决标志和x04阻挡变元等待标志设置为开启。如果不成功,则返回到步骤1重新开始;否则继续执行步骤3。
3.在这一点,链接指针被第二变元所阻挡,并且该标志已经被设置在链接指针内,表明要删除包含受阻挡链接指针的一个变元正在等待该链接指针被解阻挡。这是当第二变元解阻挡该链接指针时将被识别的情况。使用具有受阻挡删除控制对象的链接传送机制以等待第二变元“解阻挡”该链接指针。在这种情况下,第二变元将不解阻挡它,而是将为该等待变元“重新阻挡”它(存储等待变元的阻挡元对象地址,并且x01被阻挡和x08删除未决标志开启)。然后,它将使用链接传送机制来唤醒等待中的变元,把该数值传送给它,否则它将置于该链接指针中,使其实际解阻挡它。
4.该过程退出,返回通过在步骤3链接传送机制所获得的被解阻挡链接指针数值。阻挡最后的链接指针当删除一个链接,或者当先插入,在当前链接之后,或在一个任意链接之后,该函数被用于阻挡在下一个链接中的反向指针。这是将在这些情况中阻挡的最后链接指针。
1.上述阻挡一个链接指针而不等待的过程被调用,以尝试阻挡的链接指针。如果成功,则退出,返回链接指针的原始(未阻挡)的内容;否则继续到步骤2。
2.阻挡链接指针的尝试失败,因为它已经被第二变元所阻挡。如果该链接指针没有被尝试性地阻挡,转到步骤3。否则,该链接指针被第二变元尝试性地阻挡,并且该变元将暂停其阻挡并使用具有在第一变元的阻挡元对象内的暂停链接控制对象的链接传送机制来把一个指向前一链接的指针传送给它。从而使用在第一变元的阻挡元对象内具有暂停链接控制对象的链接传送机制,以等待该链接指针。当被唤醒时,退出,返回指向前一链接的一个指针。
3.在这一点,该链接指针被第二变元所阻挡,但不是尝试性的。使用与上述阻挡一个链接指针并等待相同的步骤,以等待要被解阻挡的链接指针。如果任何这些步骤失败,或者当从等待中唤醒时,在此返回到步骤1重新开始。解阻挡链接指针当解阻挡链接指针时,在前一链接内的正向指针被首先解阻挡,然后在下一链接中的反向指针可以被解阻挡。解阻挡在前一链接中的正向指针1.如果x04阻挡变元等待标志和x08删除未决标志在要被解阻挡的链接指针中都为开启,它表示要删除包含受阻挡正向指针的链接的变元正在等待。在该情况中,转到步骤2继续执行。否则,使用compareAndSwap(),来尝试用指向其新的下一个链接的指针替换受阻挡的链接指针。如果该尝试失败,这是因为其它变元在受阻挡链接指针内设置标志,从而返回到步骤1的开始处以重新开始。如果尝试成功,则退出,返回链接指针的旧的受阻挡数值,其可以使得x02迭代变元等待和/或x04阻挡变元等待标志开启,表示它是否将需要查找潜在的等待者。
2.在这一点,要删除包含受阻链接指针的链接的变元正在等待(通过链接传送机制)恢复的许可。该变元还阻挡在同一链接中的反向指针。定位该反向指针,并且从它定位由该变元所使用的阻挡元对象。
3.使用compareAndSwap()来尝试存储在受阻挡链接指针中的阻挡元对象的地址(使x01受阻挡和x08删除未决标志开启)。如果该尝试失败,这是因为另一个迭代变元把受阻挡链接指针内的x02迭代变元等待标志设置为开启,所以开始该步骤,直到成功。一旦它成功,则该链接指针现在表现为被等待变元所阻挡,其要删除包含该链接指针的链接。
4.使用具有在等待变元的阻挡元对象中的受阻挡删除控制对象的链接传送机制,以把该链接指针传送到等待变元,并且唤醒它。
5.退出,返回链接指针的旧的受阻挡数值。x02迭代变元等待标志和x04阻挡变元等待标志将是重要的,其表示是否需要查找潜在的等待者。解阻挡在下一个链接内的反向指针1.如果该链接指针被尝试性地阻挡,则它实际被不同的变元使用不同的阻挡元对象所阻挡。在这种情况中,转到步骤3继续执行。
2.使用compareAndSwap()来尝试用指向其新的前一链接的指针来替换受阻挡的链接指针。如果该尝试失败,这是因为另一个阻挡变元设置在受阻挡链接指针内的x04阻挡变元等待标志,所以重复该步骤直到它成功。当它成功时,则退出,返回该链接指针的旧的(受阻挡)数值,其可能使x04阻挡变元的等待标志开启,表示是否需要查找潜在的等待者。
3.在这一点,链接指针被不同的变元尝试性地阻挡。该变元将暂停该受阻挡链接指针,并且将使用具有在其阻挡元对象内的暂停链接控制对象的链接传送机制,以等待重新开始的许可。使用具有暂停链接控制对象的链接传送机制,以把指向新的前一链接的指针传送给它(该相同数值否则在步骤2中被置于链接指针内)。这将唤醒该等待变元,给其一个新的前一链接指针。
4.退出,不返回任何参数。该链接指针还未被改变。(如果x04阻挡变元等待标志为开启,这用于另一个变元,其已经尝试性阻挡该链接指针,并且当它解阻挡该链接指针时,它将看到它。)阻挡元/观察对象交互作用当插入一个链接时查找等待的迭代器在阻挡用来插入一个新链接的该链接指针之后,变元等待任何附加到在前一链接中的正向链接指针的迭代器前进。检查元观察对象必须检验在SharedChain对象中的有效检查元观察计数字段是否非零,并且变元观察对象必须检验在SharedChain对象中的有效变元观察计数字段是否非零。如果观察对象必须被检验,则每个的检验返回一个布尔值,表明是否阻挡变元必须等待迭代器前进。TRUE响应的数目是阻挡变元必须等待的“前进通知”的数目。对每个被检验的观察对象执行如下步骤1.如果观察对象的curPtr字段不指向在前一链接中的正向链接指针,则该观察对象是不相关的,从而该处理结束,返回FALSE。
2.如果该观察对象的curLink字段指向变元的阻挡元对象,则迭代器已经承诺等待变元解阻挡该链接指针。在这种情况下,该观察对象是不相关的,从而返回FALSE。(请注意,由于检查元不等待阻挡变元,因此这不是当为一个检查元检验观察对象时的情况。)3.如果观察对象的curLink字段(1)指向在变元阻挡之前该链接指针所指向的相同链接,或者(2)指向不同的阻挡元对象,则在任何情况中,观察对象与该变元相关。(当为一个检查元检验一个观察对象时,由于检查元不等待,因此curLink不会被看到指向一个阻挡元对象。并且对于一个变元的观察对象,如果curLink指向不同的阻挡元对象,则仅仅意味着使用该阻挡元对象的变元最近解阻挡该链接指针,但是还没有准备更新curLink。)在任何情况中,使用compareAndSwapQualified()来尝试把在观察对象的curPtr字段中的x01承诺等待者标志设置为开启。如果失败(因为curLink或者curPtr在同时改变),返回到步骤1重新开始。如果成功,变元现在承诺等待该迭代器前进,所以冲突该迭代器的任务优先级。然后使用compareAndSwap()来尝试把在观察对象curPtr字段中的x02优先级冲突标志设置为开启。如果该尝试失败(因为迭代器已经前进并且具有改变的curPtr),解除阻挡在观察对象中的优先级冲突不确定解决器(单任务阻挡元对象),然后返回FALSE。(前进的迭代器将看到在curPtr的旧数值中,x01承诺等待者标志为开启,但是x02优先级冲突标志为关闭,从而它将知道不把其前进情况通知给该变元而是等待其优先级冲突不确定解决器对象被解除阻挡,从而它可以在解除冲突之前确认其任务优先级已经被冲突)。如果尝试把x02优先级冲突标志设置为开启成功,则返回TRUE。这是一个用于变元所等待的迭代器的观察对象。(当迭代器前进并且看到在curPtr的旧数值中的x01承诺等待者和x02优先级冲突标志为开启,则它将把其前进情况通知给变元,并且解除冲突其自身的任务优先级。)4.在所有其它情况中,如果curLink包含特殊的过渡数值,它表示curPtr已经被设置,但是curLink还没有用将从curPtr解除引用的数值来设置。变元不能判断要被存储在curLink中的数值是否在它阻挡该链接指针之前还是之后获得,并且该变元不能判断它是否将需要等待迭代器前进。为了确认,使用compareAndSwapQualified()来尝试把curLink改变为特殊的错误比较数值。如果不成功(因为curLink或者curPtr被同时改变),回到步骤1重新开始。如果成功,它将阻止迭代器尝试用它从curPtr解除引用获得的任何数值来设置curLink,并且将强制它重新开始,并且再次解除引用curPtr,而这次它将看到链接指针被阻挡。按照这种方式,变元可以确认它不必等待迭代器前进,从而返回FALSE;否则继续到步骤5。
5.观察对象看起来与变元无关,但是将确认curLink数值是当前数值。使用compareAndSwap来尝试把以前提取的数值存储回curLink。如果成功,返回步骤1重新开始。否则该观察对象与迭代器无关,从而返回FALSE。
当所有观察对象已经被检验,TRUE响应的数目将是在变元可以前进之前必须前进的迭代器的数目。把该数目添加到在变元的阻挡元对象中的状态控制对象。x01承诺等待者和x02优先级冲突标志将在curPtr中对每个迭代器为开启,该迭代器在它前进时必须通知变元(减少在阻挡元对象中的状态控制对象)。该变元将等待许多通知出现。当删除一个链接时查找等待的送代器在阻挡该链接指针以删除一个链接之后,变元必须等待任何附加到在前一链接中的正向链接指针或者在要被删除的链接中的正向指针的迭代器前进。如果在SharedChain对象中的有效检查元观察计数字段是非零检查元观察对象被检验,如果在SharedChain对象中的有效变元观察计数字段是非零变元观察对象被检验。如果观察对象必须被检验,则每个的检验返回一个布尔值,表明是否阻挡变元必须等待迭代器前进。TRUE响应的数目是阻挡变元必须等待的“前进通知”的数目。对每个被检验的观察对象执行如下步骤1.如果观察对象的curPtr字段没有指向正被删除的链接中的正向指针,则进行到步骤2。否则,使用compareAndSwapQualified()来尝试把在观察对象的curPtr字段中的x01承诺等待者标志设置为开启。如果失败(由于curLink或者curPtr被同时改变),则返回到这个步骤的开始处并重新开始。如果它成功,则该变元现在承诺等待迭代器前进,所以冲突该迭代器任务的优先级。然后使用compareAndSwap()来尝试把在观察对象的curPtr字段中的x02优先级冲突标志设置为开启。如果该尝试失败(由于迭代器已经前进并且已经改变curPtr),则解阻挡在观察对象中的优先级冲突不确定解决器(单个任务阻挡元对象),然后返回FALSE。(前进的迭代器将看到在curPtr的旧数值中,x01承诺等待者标志为开启但是x02优先级冲突标志为关闭,从而它知道不把其前进情况通知给变元,而是等待其优先级冲突不确定解决器被解阻挡,从而它可以确认在解除冲突之前,其任务优先级已经被冲突)。如果把x02优先级冲突标志设置为开启的尝试成功,则返回TRUE。这是用于变元所等待的迭代器的观察对象。(当迭代器前进并且看到在curPtr的旧数值中x01承诺等待者和x02优先级冲突标志为开启,它将把其前进情况通知给该变元,并且解除冲突其自身的任务优先级。)如果步骤1没有返回TRUE,则继续执行步骤2。
2.如果观察对象的curPtr字段不指向在前一链接中的正向链接指针,则该观察对象是不相关的,从而返回FALSE;否则继续执行步骤3。
3.如果观察对象的curLink字段指向该变元的阻挡元对象,则迭代器已经承诺等待该变元。在这种情况下,该观察对象是不相关的,从而返回FALSE;否则继续进行步骤4。
4.如果观察对象的curLink字段(1)指向在被变元阻挡之前该链接指针所指向的同一链接,或者(2)指向不同的阻挡元对象,则在任何一种情况下,该观察对象与该变元相关。(当检验一个用于检查元的观察对象时,由于检查元不等待,因此curLink将不会被看到指向一个阻挡元对象。并且对于变元的观察对象,如果eurLink指向不同的阻挡元对象,则它仅仅意味着使用该阻挡元对象的变元最近解阻挡了该链接指针,但是还没有开始更新curLink。)在任何一种情况中,使用compareAndSwapQualified()来尝试把在观察对象的curPtr字段中的x01承诺等待者和x04删除等待标志设置为开启。如果它失败(因为curLink或者curPtr被同时改变),则返回步骤1重新开始。如果成功,则变元现在承诺等待迭代器前进(两次),所以冲突该迭代器的任务优先级。然后,使用compareAndSwap()来尝试把在观察对象的curPtr字段中的x02优先级冲突标志设置为开启。如果该尝试失败(因为迭代器已经前进并且已经改变curPtr),则解阻挡在观察对象中的优先级冲突不确定解决器(单个任务阻挡元对象),然后返回TRUE。(前进的迭代器将看到x01承诺等待者和x04删除等待标志都为开启,但是在curPtr的旧数值中x02优先级冲突标志为关闭。它将把curPtr中的x01承诺等待者和x02优先级冲突标志设置为开启,从而它将知道在下一次它前进时通知变元并且解除冲突其自身的任务优先级。同时,它将等待其优先级冲突不确定解决器对象被解阻挡,从而它可以确认在它最终解除冲突之前,其任务优先级已经被冲突)。如果把x02优先级冲突标志设置为开启的尝试成功,则返回TRUE;否则继续执行步骤5。在前一种情况中,这是用于该变元所等待的迭代器的观察对象。(当迭代器前进并且看到在curPtr的旧数值中的所有三个标志都为开启,则它把在curPtr中的x01承诺等待者和x02优先级冲突标志设置为开启,从而它将知道在它下次前进时通知该变元并且解除冲突其自身的任务优先级。)5.如果curLink包含特殊的过渡数值,它表示curPtr已经被设置,但是curLink还没有被用将从curPtr解除引用的数值所设置。变元不能够判断要被存储在curLink中的数值在它阻挡链接指针之前或之后获得,并且从而变元不能够判断它是否将需要等待迭代器前进。为了确定,使用compareAndSwapQualified()来尝试把curLink改变为特殊的错误比较数值。如果不成功(因为curLink或curPtr被同时改变),回到步骤1重新开始。如果成功,它将阻止迭代器尝试用它从curPtr解除引用的任务数值来设置curLink,并且将强制它重新开始并再次解除引用curPtr,并且这次它将看到链接指针被阻挡。按照这种方式,变元不能够确认它不必须等待迭代器前进,从而返回FALSE;否则,继续执行步骤6。
6.如果curLink不包含特殊的过渡数值,则该观察对象看起来与变元无关,但是应当确认该curLink数值是当前最新的。使用ompareAndSwap()来尝试把以前提取的数值存储回curLink。如果不成功,返回步骤1重新开始。否则,该观察对象与该变元不相关,从而返回FALSE。
当所有观察对象被检验时,TRUE响应的数目将是必须在变元可以前进之前前进的迭代器的数目。把该数目加到变元的阻挡元对象内的状态控制对象。然后等待出现许多通知(减小到状态控制对象)。当解阻挡链接指针时查找要唤醒的迭代变元当变元解阻挡其链接指针时,如果正向链接指针的旧(被阻挡)的数值包含开启的x02迭代变元等待标志,它意味着至少一个迭代变元可能承诺或者已经承诺等待该变元来解阻挡其链接指针。在这种情况下,用于变元的每个观察对象被检验。每个检验返回一个布尔值,表示该迭代变元是否已经承诺等待该链接指针被解阻挡。TRUE响应的数目是将被唤醒的迭代变元的数目,并且在被唤醒之后,将把它们完成等待的情况通知给阻挡变元。(当所有变元都表明它们已经完成等待,则阻挡元对象可以被重新使用)。如下步骤对每个被检验的观察对象执行1.如果观察对象的curPtr字段不指向前一链接中的正向指针,则该观察对象与未阻挡变元无关,从而返回FALSE;否则继续执行步骤2。
2.如果观察对象的curLink字段指向用于解阻挡变元的阻挡元对象(x01承诺等待者标志开启),则迭代变元已经承诺等待该链接指针被解阻挡。在这种情况下,使用compareAndSwap()来尝试把链接指针的新数值(解阻挡的)设置给curLink。如果该尝试失败(因为迭代变元把curLink中的x02优先级冲突或者x04优先级不冲突标志设置为开启),返回到该步骤的开始处,重新尝试。一旦该尝试成功,则迭代变元现在具有一个当前链接,并且解阻挡变元从curLink的旧数值得知迭代变元是否已经冲突或者还未冲突其任务的优先级,或者该信息是否不确定。如果x02优先级冲突或者x04优先级不冲突标志在curLink的旧数值中为开启,则解阻挡变元不能判断该迭代变元是否已经冲突其任务优先级。在这种情况下,增加在解阻挡变元的阻挡元对象内的状态控制对象,并且返回FALSE。(迭代变元将在尝试设置x02优先级冲突或者x04优先级不冲突标志时失败(因为解阻挡变元改变了curLink),并且当它后来再次解除引用链接指针时,将看到它被解阻挡。)同时,如果迭代变元已经冲突阻挡变元的任务优先级,则它将增加在解阻挡变元的阻挡元对象内的优先级冲突计数字段。然后,在任何一种情况中,它将减小解阻挡变元的状态控制对象,以表示优先级冲突不确定性已经被解决。否则,x02优先级冲突或x04优先级不冲突标志为开启。如果x04优先级冲突标志为开启,则增加在解阻挡变元的阻挡元对象内的优先级冲突计数字段。在任何一种情况下返回TRUE;否则继续执行步骤3。
3.如果curLink包含特殊的过渡数值,则它表明迭代变元已经设置curPtr,但是它还没有用其从curPtr解除引用的数值来设置curLink。解阻挡变元不能够判断它是否需要唤醒迭代变元。为了确认,使用compareAndSwapQualified()来尝试把curLink改变为特殊的错误比较数值。如果失败(由于curLink或者curPtr被在同时改变)则返回到步骤1重新开始。如果成功,则它将强制迭代变元在其尝试设置curLink时失败,并且当它再次解除引用curPtr时,它将看到链接指针被解阻挡。按照这种方式,解阻挡变元可以确认迭代变元将不等待它,从而返回FALSE。
4.如果curLink不包含特殊的过渡数值,则观察对象看起来与该变元无关,但是这个过程确认curLink数值是否为当前最新数值。使用compareAndSwap()来尝试把以前提取的数值存储回curLink。如果不成功,返回到步骤1重新开始。否则该观察对象与变元无关,从而返回FALSE。
当所有用于变元的观察对象已经被检验,则解阻挡变元将具有如下计数值(a)必须被唤醒并且必须通知它们已经被唤醒而不再需要等待的等待者的数目;(b)剩余优先级冲突不确定(在状态控制中)的数目,对此阻挡变元必须等待它们的解决的通知;以及(c)阻挡变元从其等待者接收的优先级冲突的数目(在优先级冲突计数中priority_bump_count)。当解阻挡链接指针时查找要被唤醒的阻挡变元当变元解阻挡其链接指针时,如果任何一个链接指针的旧数值(被阻挡)包含开启的x04阻挡变元等待标志,它意味着至少一个阻挡变元可能承诺或者必须承诺等待解阻挡变元来解阻挡其链接指针。在该情况下,每个阻挡元对象必须被检验。每一个检验返回一个布尔值,表示阻挡变元是否已经承诺等待该链接指针被解阻挡。TRUE响应的数目是要被唤醒的阻挡变元的数目,并且在唤醒之后那些阻挡变元把它们完成等待的情况通知给解阻挡变元。(当所有变元已经表明它们完成等待,则阻挡元对象可以被重新使用)。在每个阻挡元对象的检验中执行如下步骤1.如果在阻挡元对象中的等待阻挡元字段不指向解阻挡变元的阻挡元对象(忽略所有标志位),则该阻挡元对象是不相关的,从而返回FALSE;否则继续执行步骤2。
2.使用compareAndSwap()来尝试把阻挡元对象的等待阻挡元字段设置为NULL。如果该尝试失败(因为阻挡变元正在设置其内部的标志),则返回该步骤的开始处重新尝试。当最终成功时,等待阻挡元字段将为NULL,这表示阻挡变元不再等待。
3.如果x01承诺等待者标志在等待阻挡元字段的旧数值中为关闭,它表示当解阻挡变元解阻挡的链接指针时,阻挡变元还没有远到足以承诺等待。在这种情况下,返回FALSE;否则继续步骤4。
4.阻挡变元已经承诺等待解阻挡变元解阻挡其链接指针。阻挡变元必须尝试冲突该解阻挡变元的任务的优先级,并且可能足够或可能不够远到足以完成该操作并且表明该结果。如果x02优先级冲突和x04优先级不冲突标志在curLink的旧数值中都为开启,则优先级冲突是不确定的。在这种情况下,增加在解阻挡变元的阻挡元对象内的状态控制对象,并且返回FALSE;否则继续执行步骤5。(阻挡变元将在尝试设置x02优先级冲突或者x04优先级不冲突标志时失败(因为解阻挡变元把等待阻挡元字段设置为NULL),并且当它后来再次解除引用链接指针时,它将看到它被解阻挡。)同时,如果阻挡变元已经冲突解阻挡变元的任务优先级,则它将增加在解阻挡变元的阻挡元对象内的优先级冲突计数字段。然后,在任何一种情况中,它将减小变元的状态控制对象,以表明优先级冲突不确定性已经被解决。
5.x02优先级冲突或者x04优先级不冲突标志为开启。如果x02优先级冲突标志为开启,则增加在解阻挡变元的阻挡元对象内的优先级冲突计数字段。在任何情况下返回TRUE。
当所有阻挡元对象已经被检验时,解阻挡变元将具有如下计数值(a)等待者的数目,该等待者必须被它唤醒并且必须通知它已经被唤醒而不再需要等待;(b)优先级冲突不确定(在状态控制对象中)的数目,对此阻挡变元必须等待它们的解决的通知;以及(c)阻挡变元从其等待者接收的优先级冲突的数目(优先级冲突计数字段)。该信息将确定阻挡元对象何时被重新用于另一个改变函数。等待和唤醒等待变元解阻挡其链接指针该过程被从迭代变元和阻挡变元调用,其必须等待第二个变元解阻挡其链接指针。对在用于迭代变元的观察对象内的curLink字段的引用或者对具有阻挡变元的阻挡元对象的等待阻挡元字段的引用被作为一个参数而传送。这被完成使得它可以用尝试冲突第二变元的任务的优先级的结果来更新。(x01承诺等待者标志已经被设置为开启)。该函数仅仅在等待链接指针被解阻挡之后或者在确定不需要等待之后返回,因为当设置优先级冲突指示时,发现该链接指针被解阻挡。
1.冲突用于第二变元的任务的优先级,并且在步骤2使用x02优先级冲突标志作为标志位。但是,如果不需要冲突用于第二变元的任务的优先级,则在步骤2使用x04优先级不冲突标志作为该标志。
2.使用compareAndSwap()来尝试把在步骤1中确定的标志位设置为开启。如果成功,转到步骤3。否则,该尝试失败,因为第二变元已经解阻挡该链接指针并且更新相关的字段如果该字段是在观察对象内的curLink,则它现在为该迭代器指向新的链接指针;如果该字段是在阻挡元对象内的等待阻挡元字段,它现在为NULL。在任何一种情况中,没有等待中的节点,由于链接指针现在已经被解阻挡,但是没有看到在该字段的的旧数值中的x02优先级冲突或x03优先级不冲突标志的第二变元将不知道其任务优先级是否已经被冲突。因此,如果在步骤1中该优先级被冲突,则增加在第二变元的阻挡元对象中的优先级冲突计数值。然后,在任何情况中,减小在第二变元的阻挡元对象中的状态控制对象,以把优先级冲突不确定性已经被解决的情况通知给它,并且退出。(第二变元将最终等待所有优先级冲突不确定性被解决。)3.在这一点,该标志已经被设置,表示第二变元的任务优先级是否已经被冲突,所以等待第二变元解阻挡其链接指针。(当变元解阻挡其链接指针并且查找阻挡元或用于等待变元的观察对象时,它将知道其任务优先级是否被冲突)。当从等待中唤醒时,减小在第二变元的阻挡元对象中的状态控制对象,以把等待完成的情况通知给它,并且退出。(这将表明当前变元不在具有对第二变元的阻挡元对象的引用,并且当所有这种引用已经过期时,阻挡元对象可以用于另一个改变函数。)主要等待和唤醒机制状态计数器对象是当迭代器和变元等待并且相互唤醒时涉及的主要对象。该对象存在于阻挡元对象内,并且控制如下事件(a)确定阻挡元对象是否有效或无效,并且原子方法在那些状态之间转换;(b)使得使用阻挡元对象的变元等待迭代器前进;(c)使得迭代和阻挡变元等待使用阻挡元对象的变元来解阻挡其链接指针;以及(d)使得使用阻挡元对象的变元等待所有优先级冲突不确定性被解决。表15示出各种状态计数器数值以及它们的含义表15状态计数器数值
0该数值表示阻挡元对象在无效状态。为了把阻挡元对象改变为有效状态(当把它分配给一个变元时),该计数器自动从零改变为非零数值。(在完成该操作以前,在SharedChain对象中的有效阻挡元和观察计数字段的阻挡元部分被原子地增加1。 )x8000... 即,最高阶数位为1,所有其它数位为零。这是被分配给计数器以把其状态从无效改变为有效状态的数值。当计数器具有该数值时,使用阻挡元对象的变元处于稳定状态,不等待来自迭代或阻挡变元的任何种类的任何通知。如果阻挡变元已经阻挡任何链接指针,则所有等待变元将等待计数器到达小于x4000...的数值,从而该数值将使它们等待。x8000... 在该范围内的数值表示阻挡变元等待迭代器前进。数值x+/-x 是所涉及的迭代器的数目,其具有一个确定的范围。当阻挡变元查看一个观察对象时,它把适当的标志设置在curPtr中,并且计数它必须等待的迭代器的数目。当迭代器前进时,它通过把该状态计数器减小1而把它们前进的情况通知给阻挡变元。在查看所有观察对象之后,阻挡变元自动把它必须等待的数目加到其状态计数器上。然后,当任何剩余的迭代器把它们前进的情况通知给它时,它等待状态计数器减小到x8000...的稳定状态数值。当所有通知已经出现时,得知没有其它迭代器在其路径上,阻挡变元被释放,以解阻挡其链接指针。在该时间过程中,在计数器中的数值足够大,以使得需要等待链接指针被解阻挡的所有变元等待。x8000... 在这个范围内的数值表示阻挡变元等待优先级冲突不确+/-y 定性被解决。数值y是剩余的不确定性的数目,其具有与上述x相同的范围。通过查看该计数器,不能从上述阻挡变元等待迭代器前进的状态中区分出该状态。但是,在这种情况下,阻挡变元已经解阻挡其链接指针,并且当计数承诺等待者的数目,它还计数优先级冲突不确定性的数目。
当等待者遇到不确定性并且解决它时,它们减小该计数器。
同时,阻挡变元把不确定性的总数加到该计数器,并且等待它返回到x8000...的稳定状态数值。当到达该数值时,阻挡变元可以确定它知道其优先级已经被等待者冲突多少次,并且可以同样多次数地解除冲突其自身的优先级。z一旦阻挡变元已经解阻挡其链接指针并且等待所有优先级冲突不确定性被解决,则它把该计数器设置为它以前遇到的承诺等待者的数目。这将使得所有等待者被唤醒(并且当它们到达这一点时那些已经承诺等待但是还没有开始等待的等待者将立即等待失败)。当每个等待者被唤醒时,它通过把其计数器减小1,把其完成等待的情况通知给阻挡变元。从而,该数值z表示未完成的等待者的数目,该等待者还没有把它完成等待的情况通知给该变元。当计数器到达零时,阻挡元返回到无效状态,并且能够由另一个变元重新使用(由于不在有任何对它的突出成引用),并且在SharedChain对象中的有效阻挡元和观察计数字段的阻挡元部分被减小1。如果整个字段为零,则reclaim函数被释放,以消除任何过量的阻挡元或观察对象。链接传送机制链接传送机制是一个阻挡变元私下地把一个链接指针的使用传送到另一个阻挡变元所用的方法。该机制被用于两个不同的环境中,该环境使用在阻挡元对象中的不同的状态计数器对象1.如果变元1(使用阻挡元对象1)已经尝试性地阻挡在一个链接内的反向指针,然后发现在前一链接内的正向指针被变元2(使用阻挡元对象)所阻挡,变元1将暂停它的尝试性阻挡,允许变元2使用该链接指针。变元1使用链接传送机制来把一个指向前一链接的指针置于阻挡元对象2内的暂停链接控制状态计数器对象。同时,变元2已经等待该暂停链接控制对象,它当变元1把该链接指针置于此处时被唤醒。在把链接指针传送到变元2时,变元1等待在其自身的阻挡元对象内的暂停链接控制对象。当变元2完成时,它将把该链接指针传送回变元1,把向新的前一个链接的一个指针置于阻挡元对象1内的暂停链接控制对象中,从而唤醒变元1。
2.当变元1(使用阻挡元对象1)要删除一个链接时,但是发现在该链接内的正向指针已经被变元2所阻挡(使用阻挡元对象2),变元1等待在其阻挡元对象内的阻挡删除控制状态计数器对象。但是当变元2要解阻挡该链接指针时,并且发现它已经被要删除包含它的链接的一个变元所等待时,则不是解阻挡该链接指针,而是变元2重新为变元1而阻挡该指针。然后,通过把该指针存储在阻挡元对象1内的阻挡删除控制状态计数器对象中,变元2使用链接传送机制把指向下一个链接的一个指针传送到变元1。这唤醒变元1,其从它的阻挡删除控制对象检索指向下一链接的指针,并且继续,在现在已经成功阻挡在它要删除的链接内的正向链接指针。
链接传送机制同样产生作用,而不管它被使的情况如何。状态计数器对象包含指向一个链接的指针,或者反映状态计数器所属的变元的状态。表16示出可能出现在计数器中的状态数值。它们被选择为与出现在链接指针中的数位标志相一致,并且避免与链接指针相混淆(所有零是指向链中的第一链接或最后链接的一个链接指针)。
表16状态数值
x00...08 无效 这是计数器的初始值。它表示变元还没有(inactive) 开始等待接收一个链接指针的过程。x00...01 承诺等待者这是变元在它开始等待过程时存储的数(committed 值。它表示关于用于等待变元的任务的优先waiter) 级是否已经被冲突是不确定的。x00...03 优先级冲突该数值表示该变元正在等待接收一个链接(priority 指针,并且已经冲突用于变元的任务的优先bumped)级,从该变化它将接收链接指针。x00...05 优先级不冲该数值表示变元等待接收一个链接指针,
突 并且已经确定不需要冲突用于变元的任务(priority not 的优先级,从该变元它将接收该链接指针。
bumped)预先不知道传送该链接指针的变元是否在要接收该链接指针的变元准备完成该操作之前、过程中或者之后传送该链接指针。把一个链接指针传送到另一个变元当一个变元要把一个链接指针传送到第二变元时,它知道用于该第二变元的该阻挡元对象,并且用在该阻挡元对象内的适当状态计数器进行工作。使用如下步骤来传送链接指针1.从状态计数器对象获得当前计数器数值。
2.使用compareAndSwapCounter(),来尝试把该计数器从它的当前数值改变为链接指针数值。如果该尝试失败(由于所接收变元正在设置在该计数器内的标志),返回步骤1重新开始;否则继续执行步骤3。
3.如果计数器的旧数值是x08无效数值,它表示第二变元还没有开始等待,并且将不实际等待或者它将冲出第一变元的任务优先级。在这种情况下,传送功能完成,否则,继续进行步骤4。
4.如果计数器的旧数值是x01承诺等待者,则第二变元已经开始等待过程,并且在它实际等待之前,它尝试冲突第一变元的任务优先级,但是第一变元不能够得知其任务优先级是否被冲突。增加在第一变元的阻挡元对象中的状态控制对象,以表示最终必须被解决的优先级冲突不确定性,并且该传送功能完成。(第一变元将最终等待所有优先级冲突不确定性被解决,并且第二变元将减小第一变元的状态控制对象以表示该解决。第二变元将不实际等待链接传送)。否则,如果计数器的旧数值不是x01承诺等待者,则继续执行步骤5。
5.如果计数器的旧数值是x03优先级冲突,则第二变元已经冲突第一变元的任务优先级。在这种情况下,增加在第一变元的阻挡元对象中的优先级冲突计数值,并且该传送功能结束。(第一变元将最终解除冲突其自身的任务优先级。同时,第二变元将从其等待中被唤醒)。
6.否则,计数器的旧数值是x05优先级不冲突,表示第二变元已经确定它不需要冲突第一变元的任务优先级。在这种情况下,传送功能结束。(第二变元将在其等待中被唤醒)。等待接收一个被传送链接指针当变元要从第二变元接收一个链接指针时,它知道第二变元将传送指向在第一变元的阻挡元对象内的特定状态计数器对象的链接指针。如下步骤描述等待接收链接指针的过程。
1.使用在状态计数器对象上的compareAndSwapCount()来尝试把该计数器从其所期望的x08无效数值改变为x01承诺等待者数值。如果该尝试失败,这是因为第二变元已经传送该链接指针。在这种情况下,转到步骤6;否则继续执行步骤2。
2.该尝试成功并且计数器的新数值表示如果第二变元要立即传送链接指针,它将不知道其任务优先级是否已经被冲突。调用tryBump()来尝试冲突第二变元的任务优先级,并且在下面步骤中使用x03优先级冲突数值;但是,如果不需要冲突该优先级,使用x05优先级不冲突数值来替代。
3.使用compareAndSwapCount()来尝试把计数器从它的期望x01承诺等待者数值改变为在步骤2中确定的数值。如果该尝试失败,则这是因为第二变元刚刚传送该链接指针。在这种情况下,转到步骤5;否则,继续执行步骤4。
4.计数器现在包含表示第二变元的优先级是否被冲突的指示,从而等待第二变元传送该链接指针。这相当于等待状态计数器变为除了在步骤3中设置的数值之外的一些其它数值。当第二变元传送该链接指针时,它将唤醒第一变元。当被唤醒时,继续执行步骤6。
5.在这一点,第二变元已经传送该链接指针,但是将不知道其优先级是否被冲突。如果该优先级在步骤2中被冲突,则增加在第二变元的阻挡元对象内的优先级冲突计数字段。在任何一种情况下,减小在第二变元的阻挡元对象中的状态控制对象,以把优先级冲突不确定性已经被解决的情况通知给它。
6.在这一点,第二变元已经传送该链接指针。从状态计数器中检索该链接指针。
7.把状态计数器设置回x08无效数值。该操作可以安全地完成,因为没有其它变元将尝试把一个链接指针传送到使用该状态计数器对象的第一变元,直到第一变元采取进一步的行动提示另一个变元来操作时为止。回收(reclaim)过量的阻挡元或观察对象在链接指针内的x02迭代变元等待和x04阻挡变元等待标志以及在SharedChain对象中的有效检查元观察计数和有效变元观察计数字段被用于表明何时需要一个变元搜索通过观察和/或阻挡元对象的列表。当不需要进行搜索时所做的搜索操作是一个令人所不希望的性能开销。另外,希望保持观察和阻挡元对象的列表合理地简短,使得当搜索必须时,没有过量的无效对象被搜索。最好,SharedChain在每个列表中保持最小数目的对象(当前为4),并且当有机会回收过量的对象时,它回收在此时存在的一半过量对象。其目的是消除过量的对象但是不要太快。
阻挡元和观察对象被保持在单个链接表中,使得新的对象可以被原子地添加到该列表的开头,而不需要锁定来完成该操作。当没有对该对象的突出引用时,它们可以被删除。已知当在SharedChain对象内的有效阻挡元和观察计数字段被减小为零时,已知没有突出的引用。
当非原子迭代器完成其(非原子)观察对象时,或者阻挡元对象的状态控制(status_control)状态计数器被设置为0,使得没有(更多的)等待者具有对它的引用,则有效阻挡元和观察计数字段被原子地减小1。但是,如果作为减小的结果整个字段为0,然后不是简单地减小,如果具有一个或多个额外的对象,还同时把回收正在进行标志(在该字段中的高阶数位)设置为开启。当减小有效阻挡元和观察计数字段时使用如下步骤以尝试把回收正在进行标记设置为开启,并且如果成功,则执行回收函数1.把有效阻挡元和观察计数字段提取为一个临时副本,并且对其执行减小操作。如果结果为0,则转到步骤2。否则使用compareAndSwap()来尝试把减小的副本存储回该字段。如果该尝试失败,则它表示该字段被在同时改变,从而返回到步骤1的开始处重新开始。如果该尝试成功,该减小操作完成,但是由于没有对观察和/或阻挡元对象的突出引用(或者回收操作已经正在进行),则在此时没有可回收的东西,从而只好退出。
2.在这一点,没有对阻挡元和观察对象的突出引用,如果存在过量的对象则可以完成回收。从SharedChain对象中提取主要观察存在计数或者次要观察存在计数字段(无论哪个有效)成为一个临时副本。该字段分别包含用于检查元和用于变元的存在观察对象的数目。
3.从SharedChain对象提取阻挡元和观察存在计数字段成为一个临时副本。
4.使用在步骤2和3中获得的字段来确定在此是否有任何过量的阻挡元对象、用于检查元的观察对象或者用于变元的观察对象。如果在此没有任何过量的对象,则把在步骤1中获得的有效阻挡元或观察计数字段的副本中的回收正在进行标志设置为开启。
5.使用compareAndSwapQualified()来尝试把该临时副本存储回有效阻挡元和观察计数字段。如果失败(因为该有效阻挡元和观察计数字段或者阻挡元和观察存在计数字段在同时改变),然后返回步骤1重新开始。如果该尝试成功,则根据步骤4的结果,该回收或者正在进行或者不正在进行。如果不正在进行,则无事可做,只好退出。
6.在这一点,回收正在进行,并且几个字段的内容已经被从SharedChain对象中提取以供以后使用。同时,字段本身可以在尝试进行回收过程时改变。如果没有过量的阻挡元对象,则转到步骤10。
7.根据在步骤3中提取的计数值,在此有过量的阻挡元对象。把过量的被提取阻挡元和观察存在计数字段的阻挡元部分减半。直到compareAndSwapQualified()操作在步骤16中为止,该改变将不生效。
8.以第一阻挡元对象为开始(从主要阻挡元列表头或次要阻挡元列表头字段为开始,无论哪一个有效),查找下一个阻挡元对象,并且步进通过该列表,直到要被回收的阻挡元对象的数目被经过。被经过的阻挡元对象是要被抛弃的对象,并且当前阻挡元对象要成为该列表中的新的第一阻挡元对象。在该列表中现在有比所期望更多的阻挡元对象,但是不会更少。把指向新的第一阻挡元对象的指针存储到在主要阻挡元列表头或者次要阻挡元列表头字段中,无论哪个无效。直到compareAndSwapQualified()操作在步骤16中成功为止,该改变毫无意义。
9.切换(toggle)在被提取的阻挡元和观察存在计数字段的阻挡元部分中的高阶数位。这将交换(swap)主要阻挡元列表头和次要阻挡元列表头,对于有效的一个。直到compareAndSwapQualified()操作在步骤16中成功为止,这毫无含义。但是,当它成功时,要被删除的阻挡元对象不再可见于该列表中,并且可以随意抛弃。
10.如果没有用于检查元的过量观察对象,转到步骤14。
11.在此具有用于检查元的观察对象,根据在步骤2中提取的计数值。把过量的被提取的主要观察存在计数或者次要观察存在计数字段的检查元部分减半。并且还把所提取阻挡元和观察存在计数字段的观察部分减小相同的量。直到compareAndSwapQualified()操作在步骤16中成功为止,这些改变将不变为有效。
12.类似于对阻挡元对象的描述,步进通过要被回收的观察对象的数目,以查找期望变为该列表中的新的第一观察对象的观察对象。再次,在列表中可能有比所期望更多的检查元观察对象,但是不会更少。把指向新的第一检查元观察对象的指针存储到在主要检查元观察链头或者次要检查元观察链头字段中,无论哪个有效。直到compareAndSwapQualified()操作在步骤16中成功为止,该改变将毫无含义。
13.切换在所提取的主要观察存在计数或者次要观察存在计数字段的检查元部分中的高阶数位。这将交换主要检查元观察列表头和次要检查元观察列表头,对于有效的一个。直到compareAndSwapQualified()操作在步骤16中成功为止,这毫无含义。但是,当它成功时,要被删除的观察对象不再可见于该列表中,并且可以随意抛弃。
14.如果没有用于变元的过量观察对象,则转到步骤15。否则,对变元观察对象完成与在步骤11-13中对检查元观察对象所作的处理相等价的处理。
15.如果存在用于检查元或变元的过量观察对象,则把被提取的/更新的主要观察存在计数或者次要的观察存在计数字段复制到SharedChain对象内的主要观察存在计数或者次要观察存在计数字段,无论哪个无效。这个被更新字段将包含新的检查元观察计数和表示主要检查元列表头或次要检查元列表头是否有效的指示,和/或新的变元观察计数和表示主要变元列表头或次要变元列表头是否有效的指示。直到compareAndSwapQualified()操作在步骤16成功为止,这毫无含义。另外,如果存在用于检查元或变元的过量观察对象,则切换在被提取的阻挡元和观察存在计数字段的观察部分中的高阶数位。这将交换主要观察存在计数和次要观察存在计数字段,对于有效的一个。直到compareAndSwapQualified()操作在步骤16成功为止,这毫无意义。
16.该步骤是整个回收操作的原子点。使用compareAndSwapQualified()来尝试把阻挡元和观察存在计数字段原子地取代为对被提取数值的更新,同时保证该字段或有效阻挡元和观察计数字段没有同时改变。如果该操作成功,则转到步骤20。否则由于在操作时具有有效的阻挡元和/或观察对象,或者现在比回收处理开始时具有更多的阻挡元和/或观察对象存在,因此承诺改变的尝试失败。
17.与在步骤2中相同,从SharedChain对象中提取主要观察存在计数或次要观察存在计数字段(无论哪个有效)。然后如步骤3中提取阻挡元和观察存在计数字段。
18.从SharedChain对象中提取有效阻挡元和观察计数字段。如果除了回收正在进行(reclaim-in0progress)标志之外,它们不全为0,则转到步骤19。否则除了回收正在进行标志之外,它全为0,从而回收处理被重新尝试。使用compareAndSwapQualified()来存储回有效阻挡元和观察计数字段,确定它与该阻挡元和观察存在计数字段还仍然有效。如果该操作失败,转到步骤17重新尝试。否则,如果成功,转到步骤6重新尝试回收处理。
19.由于现在具有有效的阻挡元或观察对象,则回收函数必须等待,直到它们全部无效为止,从而使用compareAndSwapQualified()来尝试把回收正在进行标志设置为关闭。如果该操作失败(由于有效阻挡元和观察计数字段或者阻挡元和观察存在计数字段再同时改变),则返回到17,重新开始。如果成功,则退出;当整个有效阻挡元和观察存在计数字段最终回到0时,该回收操作将被重新尝试。
20.在这一点,回收已经成功。如果阻挡元对象被回收,则在阻挡元和观察存在计数字段的阻挡元部分中的被切换的高阶数位已经使得主要阻挡元列表头和次要阻挡元列表头字段对于哪个有效和哪个无效来交换了角色,并且新的有效列表头已经绕过了要被删除的阻挡元对象。类似地,如果任何观察对象被回收,则在阻挡元和观察存在计数字段的观察部分中的被切换的高阶数位已经使得主要观察存在计数和次要观察存在计数字段对于哪个有效和哪个无效来交换了角色,并且新的有效字段的任何部位中的被切换的高阶数位独立地表示它是否为用于现在有效的检查元或变元观察对象的主要链头或次要链头字段。一个用于检查元或变元观察对象的新的有效列表头字段已经绕过要被删除的观察对象。
21.使用compareAndSwap()来尝试把在有效阻挡元和观察计数字段中的回收正在进行标志设置为关闭。如果该操作失败,则重复进行直到成功。
22.删除在上述步骤中回收的过量阻挡元、检查元观察、和/或变元观察对象。扼要重述上文所述的优选实施例的一些操作特征可以综述如下。使用SharedChain对象以及其相关的数据结构,可以同时在列表中插入和/或删除多个链接,而没有冲突。这是通过阻挡在链接级的访问而不是在整个列表级的访问而实现的。特别地,在同一时刻,一个检查元对象“保护”(防止被另一个对象所改变)仅仅一个链接,而一个迭代变元对象“保护”两个连续链接的一个滑动窗口。在插入点处,变元保护在两个连续链接中的至少一些数据(不包括被插入的链接),并且在删除点处,变元保护至少在三个连续链接(包括要被删除的链接)中的至少一些数据。
一个检查元对象通常自由遍历一个链接表,尽管一个变元对象已经阻挡它的一部分以改变它。该检查元可以遍历通过(绕过)被变元所阻挡的部位。
尽管变元能够遍历一个列表以确定要插入或删除一个链接的地点,它还可以在任意位置删除链接和插入链接而不需要遍历(即,在该表中部给出一个任意链接)。双链接(正向和反向指针)对于特定不需要列表遍历的插入/删除来说是需要的。本发明的优选实施例的全部可能性在这样一个双链接表中实现,其中客户具有指向列表中的链接的指针,并且多个客户可能同时跳到任意列表位置以插入/删除链接。同时对在链接列表中的任意点执行多次删除和插入的能力不取决于链接的参考计数。
一种排序关系可以对在SharedChain对象中的链接定义。例如,每个链接可以包含一个文本数据字段,例如名称,其中链接被排序使得文本计数字段按照字母次序排列。由一个变元遍历该列表以定位一个插入点,并且在插入过程中保护相邻链接中的指针,如果该排列关系对该列表确定的话,使得SharedChain对象对该链接维持这种排序关系。变元遍历该列表,并且把要被插入的链接的适当数据字段与现有链接的字段相比较,直到定位正确的插入点为止。
通过把链接置于预定的地址边界(在优选实施例中为16字节)并且把在链接中的指针置于预定的地址边界(在该优选实施例中为8字节),可以使用一些地址位作为标志。这具有在交换地址本身的相同原子操作(例如,compareAndSwap())中交换(swap)关键标志位的优点。尽管本发明的特定实施例已经单独参照特定的例子而公开,但是本领域内的专业人员应当认识到可以在下面的权利要求的范围内在形式和细节上作出其它改变。
权利要求
1.一种用于维护链接表的方法,其中包括如下步骤为所述链接表建立一个辅助数据结构,所述辅助数据结构包括对由更新任务所使用的所述链接表的外部引用;通过所述辅助数据结构启动用于更新所述链接表的第一更新任务;在所述辅助数据结构中记录阻挡数据,以阻挡通过所述辅助数据结构访问所述链接表的其它更新任务改变所述链接表的第一部分,所述第一部分小于所述链接表的所有单元;以及通过执行包括如下动作中的一个动作,在所述链接表的所述第一部分中更新所述链接表,所述动作包括(a)从所述链接表中删除在所述链接表的所述第一部分中的一个单元,以及(b)在所述链接表的所述第一部分内把一个单元插入到所述链接表。
2.根据权利要求1所述的方法,其中所述辅助数据结构包括旁路单元的列表,每个旁路单元包括被紧接着在所述列表的一个阻挡部分之后的列表单元的引用,其中所述记录阻挡数据的步骤包括把一个对所述链接表的所述第一部分的第一列表单元的引用改变为引用一个旁路单元,其中遍历所述链接表但是不改变所述链接表的任务通过经过所述链接表的所述第一部分的所述旁路单元遍历所述链接表。
3.根据权利要求1所述的方法,其中所述链接表示一个双链接表。
4.根据权利要求1所述的方法,其中被所述记录阻挡数据的步骤所阻挡的所述链接表的所述第一部分包含最多3个的链接。
5.根据权利要求1所述的方法,进一步包括如下步骤启动用于通过所述辅助数据结构更新所述链接表格第二更新任务;在所述辅助数据结构中记录阻挡数据,以阻挡除了通过所述辅助数据结构访问所述链接表的所述第二更新任务之外的其它任务改变所述链接表的第二部分,所述第二部分少于所述链接表的所有单元;以及通过执行包括如下动作中的一个动作,在所述链接表的所述第二部分中更新所述链接表,所述动作包括(a)从所述链接表中删除在所述链接表的所述第二部分中的一个单元,以及(b)在所述链接表的所述第二部分内把一个单元插入到所述链接表,更新在所述第二部分中的所述链接表的所述步骤与更新在所述第一部分中更新所述链接表的所述步骤同时执行。
6.根据权利要求1所述的方法,进一步包括如下步骤发出指向在所述链接表中的任意链接的指针,以定位一个点用于改变所述链接表,其中被所述记录阻挡数据步骤所阻挡的所述第一部分包括至少一部分所述任意链接。
7.根据权利要求1所述的方法,其中所述辅助数据结构是在面向对象编程结构的一个类层级中的一个对象。
8.根据权利要求7所述的方法,其中所述类层级包括用于遍历所述链接表而不改变它的第一类,以及用于遍历所述链接表并且改变它的对象的第二类。
9.根据权利要求8所述的方法,其中所述类层级进一步包括用于遍历所述链接表而不改变它并具有列表级阻挡访问的对象的第三类,用于遍历所述链接表而不改变它并具有链级阻挡访问的对象的第四类,用于遍历所述链接表并改变它并具有列表级阻挡访问的对象的第五类,以及用于遍历所述链接表并且改变它并具有链级阻挡访问的对象的第六类,所述第三和第四类继承所述第一类,以及所述第五和第六类继承所述第二类。
10.根据权利要求1所述的方法,其中排序关系被确定用于所述链接表。
11.一种用于更新在多任务计算机系统中的双链接表的方法,包括如下步骤识别在所述双链接表的相关区域中的第一组连续链接,所述第一组连续链接少于所述双链接表的所有链接;阻挡除了第一任务之外的其它任务改变所述第一组连续链接的链接的至少一些部分,同时不阻挡除了所述第一任务之外的其它任务改变不包含在所述第一组中的所述双链接表的链接;通过执行包括如下动作中的一个动作,在所述第一组中改变所述双链接表,所述动作包括(a)从所述双链接表中删除所述第一组的一个链接,以及(b)把一个链接在所述第一组的两个链接之间插入到所述双链接表,所述操作由所述第一任务所执行;以及在执行所述改变步骤之后,解除阻挡除了所述第一任务之外的其它任务改变所述第一组的链接的至少一些部分。
12.根据权利要求11所述的方法,其中被所述阻挡任务的步骤所阻挡的所述链接表的所述第一组连续链接包含最多3个的链接。
13.根据权利要求11所述的方法,其中识别第一组连续链接的所述步骤包括接收指向所述链接表内的一个任意链接的指针,以定位用于改变所述链接表的点,所述任意链接在所述第一组中。
14.根据权利要求11所述的方法,进一步包括如下步骤识别在所述双链接表的相关区域中的第二组连续链接,所述第二组连续链接少于所述双链接表的所有链接;阻挡除了第二任务之外的其它任务改变所述第二组连续链接的链接的至少一些部分,同时不阻挡除了所述第二任务之外的其它阻挡任务改变不包含在所述第二组中的所述双链接表的链接;通过执行包括如下动作中的一个动作,在所述第二组中改变所述双链接表,所述动作包括(a)从所述双链接表中删除所述第二组的一个链接,以及(b)把一个链接在所述第二组的两个链接之间插入到所述双链接表,所述操作由所述第二任务所执行;以及在执行在所述第二组中改变所述双链接表的所述步骤之后,解除阻挡除了所述第二任务之外的其它任务改变所述第二组的链接的至少一些部分;其中,在所述第二组中改变所述双链接表的所述步骤是在阻挡除了所述第一任务之外的其它任务改变所述第一组的链接步骤之后,并且在解除阻挡除所述第一任务之外的其它任务改变所述第一组的链接之前执行的。
15.一种用于维护链接表的计算机程序产品,所述计算机程序产品包括记录在计算机可读介质上的多个计算机可执行指令,所述程序执行如下步骤为所述链接表建立一个辅助数据结构,所述辅助数据结构包括对由更新任务所使用的所述链接表的外部引用;通过所述辅助数据结构启动用于更新所述链接表的第一更新任务;在所述辅助数据结构中记录阻挡数据,以阻挡通过所述辅助数据结构访问所述链接表的其它更新任务改变所述链接表的一部分,所述部分小于所述链接表的所有单元;以及通过执行包括如下动作中的一个动作,在所述链接表的所述部分中更新所述链接表,所述动作包括(a)从所述链接表中删除在所述链接表的所述部分中的一个单元,以及(b)在所述链接表的所述部分内把一个单元插入到所述链接表。
16.根据权利要求15所述的计算机程序产品,其中所述辅助数据结构包括旁路单元的列表,每个旁路单元包括被紧接着在所述列表的一个阻挡部分之后的列表单元的引用,其中所述记录阻挡数据的步骤包括把一个对所述链接表的所述第一部分的第一列表单元的引用改变为引用一个旁路单元,其中遍历所述链接表但是不改变所述链接表的任务通过经过所述链接表的所述第一部分的所述旁路单元遍历所述链接表。
17.根据权利要求15所述的计算机程序产品,其中所述链接表示一个双链接表。
18.根据权利要求15所述的计算机程序产品,其中被所述记录阻挡数据的步骤所阻挡的所述链接表的所述第一部分包含最多3个的链接。
19.根据权利要求15所述的计算机程序产品,其中所述程序进一步包括如下步骤启动用于通过所述辅助数据结构更新所述链接表格第二更新任务;在所述辅助数据结构中记录阻挡数据,以阻挡除了通过所述辅助数据结构访问所述链接表的所述第二更新任务之外的其它任务改变所述链接表的第二部分,所述第二部分少于所述链接表的所有单元;以及通过执行包括如下动作中的一个动作,在所述链接表的所述第二部分中更新所述链接表,所述动作包括(a)从所述链接表中删除在所述链接表的所述第二部分中的一个单元,以及(b)在所述链接表的所述第二部分内把一个单元插入到所述链接表,更新在所述第二部分中的所述链接表的所述步骤与更新在所述第一部分中更新所述链接表的所述步骤同时执行。
20.根据权利要求15所述的计算机程序产品,所述计算机程序进一步执行如下步骤发出指向在所述链接表中的任意链接的指针,以定位一个点用于改变所述链接表,其中被所述记录阻挡数据步骤所阻挡的所述第一部分包括所述任意链接。
21.根据权利要求15所述的计算机程序产品,其中所述辅助数据结构是在面向对象编程结构的一个类层级中的一个对象。
全文摘要
一种链接表具有相关的辅助数据结构,包含对由更新任务所使用的链接表的外部引用。该辅助数据结构被用于阻挡该链接表的子集被其它任务所改变。最好,该链接表是双链接表,并且表维护是使用面向对象的编程技术实现的。该辅助数据结构是一个对象,该对象包括迭代器对象,包括检查元对象和变元对象、阻挡元对象和观察对象。迭代器对象用于客户从外部访问该链接表。一个检查元对象遍历该列表而不改变它;而一个变元改变该列表,并且也可能遍历该列表。检查元和变元都具有相关的观察对象,该观察对象包含指向实际列表单元的指针。变元还具有相关的阻挡元对象,该阻挡元对象阻挡对于所选择列表单元的访问。
文档编号G06F5/06GK1332416SQ0112127
公开日2002年1月23日 申请日期2001年6月14日 优先权日2000年6月15日
发明者理查德·K·柯卡曼 申请人:国际商业机器公司
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1