用于对数据结构的实例进行操作的方法和系统的制作方法

文档序号:6466680阅读:173来源:国知局

专利名称::用于对数据结构的实例进行操作的方法和系统的制作方法
技术领域
:本发明涉及对多线程软件的开发和处理,尤其涉及对数据结构的实例进行操作的方法和系统。
背景技术
:在过去的二十多年的时间里,随着微电子技术的迅猛发展,计算机系统的性能和容量发生了爆炸性的增长。较多的计算资源意味着可以按并行的方式来同时执行更多的操作。因此,并行的体系结构以及并行的软件开发,在信息处理中发挥越来越核心的作用。一个进程是在计算机系统上运行的一个程序或程序的一部分,或者是被某个程序执行的步骤的相关序列。每个进程包括一个或多个线程。线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行。所以线程基本上是轻量级的进程,它负责在单个程序里执行任务。通常由操作系统负责多个线程的调度和执行。数据结构是一种数据的组织方案,例如记录或数组,籍此有助于解释数据或执行对数据的操作。一数据结构的一实例,是指一种数据结构的具体实施对象。对凄大据结构的实例的处理,在进程或程序中经常采用多线程处理,这可以充分利用系统资源,缩短程序响应时间,改善用户体验;如果程序中只使用单线程,那么程序的速度和响应无疑会大打折扣。多线程软件使得多个线程可以并行的工作以完成多项任务,以提高系统的效率。线程是在同一时间需要完成多项任务的时候被实现的。但是,程序采用了多线程后,就必须认真考虑线程调度的问题。如果调度不当,要么造成程序出错,要么造成荒谬的结果。众所周知,与顺序执行的软件相比,多线程软件更加难以开发。由于多个线程之间可能存在的未预料到的冲突,具有并行体系结构的程序经常包含程序缺陷。尤其是,如果没有合适的同步机制,并行地访问共享的数据结构将产生无法预料的错误。到目前为止,人们通常使用两种方法来开发多线程软件。基于锁(lock-based)的方式和无锁(lock-free)的方式。对于多线程编程和多线程并行处理,基于锁的方式是一种传统的方法。该6方法利用加锁来实现同步,以便对共享资源进行访问。常用的同步原语(Synchronizationprimitives)如互斥体(mutexes)、旗语(semaphores)和关4建部件(criticalsections)。这些同步原语通常#1用于确保某些特定的部分代码不会被同时执行,否则将会破坏共享存储结构。如果一个线程试图获取已经被其它线程持有的锁,则该一个线程将会被阻塞(block)直至该锁被释放为止。例如,在程序中,很多任务必须以确定的先后秩序执行,对于两个线程必须以先后秩序执行的情况,可以用线程锁来处理。线程锁的大致思想是如果线程A和线程B会分别执行实例的两个函数a和b,如果A必须在B之前运行,那么可以在B进入b函数时让B进入waitset,直到A执行完a函数再把B从waitset中激活。这样就保证了B必定在A之后运行,无论在之前它们的时间先后顺序是怎样的。互斥锁(mutual-exclusionlocks)是目前常用的一种机制,用于进程或线程间的同步。其简单并且容易实施。在高性能应用的并行计算环境里,这种简易性则无法实现。当使用大量的锁并且有许多线程并行执行时,互斥锁的可扩展性不佳。对于共享数据的并行访问,需要复杂的细粒度的锁策略,来将没有冲突的操作设置为并行执行。要保持良好的性能,这种策略很难设计,并且可能隐含问题,如死锁或优先级倒置。由于多种已知的原因,使得不希望线程:帔阻塞。一个明显的原因是,如果一个线程被阻塞,则该线程在该期间无法完成任何任务。如果被阻塞的线程正在执行一个高优先级的任务,或者正在执行一个实时的任务,就更加不希望该线程被阻塞。此外,多个锁之间的某些冲突还可能导致一些错误的状态,如死锁、活锁或优先级倒置(deadlock,live-lock,orpriorityinversion)。使用锁还涉及在粗粒度的锁和细粒度的锁两个方面之间进行折衷,粗粒度的锁可能会显著减少并行执行的机会,细粒度的锁需要更加细致的设计并且容易程序缺陷。不加锁(lock-free)的方式是多线程软件的开发和处理的另一种选择。Lock-free和wait-free才几制,主要4吏用由硬/f牛才是供的原子原语。大部分通用的硬件均提供这种原子原语指令集。"比较并交换(compareandswap,即CAS)"是最常用的原子原语之一。该原子原语使用三个参数(argument):—个内存地址、一个原始值(已有值)和一个新的值。如果上述内存地址存有一个原始值,则用新的值替换该原始值,否则存储的值不变。重要的是,硬件确保"比较并交换"操作被原子地执行。该操作的成功才丸行将返回一个值1或0,并^皮汇报给程序。这允许一个算法从内存中读取数据,修改该数据,然后只有在没有其它线程同时修改该内存的数据的情况下写回修改后的数据。上述基于锁的方法和不加锁的方法,各有如下优缺点。基于锁的方法(Lock-basedapproach)无锁的方法(Lock-freeapproach)可扩展性不好。在进入和离开程序关键部分时,线程需要等待。好。有多个线程在执行。鲁棒性不好。一个线程的异常退出可能会阻碍其它线程。例如,死锁。好。即使一个线程死掉,其它线程仍然得以执行。容易开发性相对容易。线程的算法(机制)与顺序执行的线程相似。获得锁的线程可以阻塞其它未得到锁的线程的执行。非常困难。线程的算法(机制)与顺序执行的线程经常完全不同。并且,有些操作效率非常低。经常需要i正明线程之间的复杂逻辑的正确性。此外,Fraser提到了一种基于MCAS和W-Locks的混合机制(见Practicallock-freedom,byKeirFraser,2004)。运行时的性能反馈被用于根据当前的竟争水平动态选择使用哪种机制。该机制中使用了运行时概要和同步原语之间的切换。
发明内容鉴于已有技术的不足,本发明提供了一种新的对数据结构的实例进行操作的方法和系统。对数据结构的实例进行操作的方法包括为至少一可无锁的操作请求获取一第一锁的弱锁,以便对该数据结构的所述实例进行4喿作;响应于该至少一可无锁的操作完成获取弱锁,执行该至少一可无锁的操作对该数据结构的实例进行的操作;为一不应无锁的操作请求获取所述第一锁的强锁,以便对该数据结构的所述实例进行操作;以及响应于该不应无锁的操作完成获取该强锁,执行该不应无锁的操作对该数据结构的实例进行的操作。本发明还提供了一种对数据结构的实例进行操作的系统。该系统包括弱8锁装置,用于为至少一可无锁的操作请求获取一第一锁的弱锁,以便对该数据结构的所述实例进行操作;可无锁的操作执行装置,用于响应于该至少一可无锁的操作完成获取弱锁,执行该至少一可无锁的操作对该数据结构的实例进行的操作;强锁装置,用于为一不应无锁的操作请求获取所述第一锁的强锁,以便对该数据结构的所述实例进行操作;以及不应无锁的操作执行装置,用于响应于该不应无锁的操作完成获取该强锁,执行该不应无锁的操作对该数据结构的实例进行的操作。与已有技术相比,根据本发明的上述方法和系统可以提高对数据结构的实例进行操作的效率。图la示意性地示出了已有技术中基于锁的方法的机制。图lb示意性地示出了已有技术中无锁实现的方法。图2a示意性地示出了已有技术中基于锁的方法的异常退出的情况。图2b示意性地示出了已有技术中无锁实现的方法的异常退出的情况。图3示出了根据本发明一实施例的用于数据结构的实例进行操作的方法。图4a和图4b示出了根据本发明一实施例的操作执行情况。图5a和图5b示出了与本发明实施例相对比根据已有技术的一实施例的操作执行情况。具体实施例方式数据结构是一种数据的组织方案,例如记录或数组,籍此有助于解释数据或执行对数据的操作。一数据结构的一实例,是指一种数据结构的具体实施对象。对于涉及多线程处理的一数据结构或数据结构实例,为了确保在多线程之间该数据结构的一致性(Coherence)或对该数据结构实例操作的正确性,对该数据结构加锁是一种常用的方法。本发明也采用加锁的方式来确保对数据结构操作的正确性。本发明所利用的锁的原理本身或用锁来保护数据结构的锁机制本身,与已有技术相比是相似的。例如,对于需要获取锁才能处理的数据结构实例,只有一操作获取锁之后才能进行处理。对于何种操作进行加锁,附加何种类型的锁,本发明的一实施例在这两方面与已有技术是不同的。此外,根据本发明的另一实施例,在获取不同类型的锁之后,持有锁的操作所允许执行的操作与已有技术相比是不同的。以下结合附图详细说明。不同的已有技术在何种情况下需要锁,采取了不同的策略。例如,基于锁的方法,所有的进程或操作都用锁来保护。这样,能够确保所涉及的数据结构的安全性,但是,可扩展性较低。如图la和图2a所示。图la示意性地示出了已有技术中基于锁的方法的机制。其中,有四个线程al、a2、a3和a4需要执行。如果线程al获取了锁并开始执行,则其它三个线程被阻塞。在线程al完成执行后,释放所持有的锁。这时,其它三个线程尝试获取锁。与线程al类似,获取锁的进程执行,其它线程被阻塞。这样,在进入和离开程序关^l建部分时,多个线程需要等待。线程的算法或机制与顺序执行的线程相似。获得锁的线程可以阻塞其它未得到锁的线程的执行。但是,如图2a所示,这种基于锁的方式的鲁棒性确不好。图2a示意性地示出了已有技术中基于锁的方法的异常退出的情况。其中,一个持有锁的线程,如线程la,异常退出可能会阻碍其它线程。例如,线程la发生死锁,其持有的锁未被释放,则其它等待的线程就会长时间处于不必要的等待状态。根据已有技术对于锁的一个具体应用如下例l。例如,一个传统的堆栈具有如下的布局。对于已有技术的多线程或多操作的并行处理,这样的堆栈是不安全的。例lStackinstance:__top:Node_size:int为确保对该堆栈操作的正确性,根据已有技术可以采用如下例2加锁(lock:LockType)的方式来进行。例如,在堆栈的实例上加锁。这样,在对该堆栈进行操作前,首先请求获取该锁。获取锁的操作或线程,可以对该堆栈进行操作,并在操作完成后释放锁。这时,其它需要对该线程进行的操作被阻塞,这些被阻塞的线程可以反复尝试获取锁,直至得到锁为止。例2Stackinstance:__lock丄ockType_top:Node_size:int对于每个堆栈的操作,如push()、pop()或clone()等等,可以调用lock.lock()来请求获取锁,调用lock.unlock()来释^:锁。这样,可以确保每次只有一个线程对堆栈进行操作。在根据本发明的一实施例中,如下例3所示,可以采用与已有技术中设置读锁和写锁类似的方法,将该锁设置为包括弱锁rLock:WeakLock和强锁wLock:StrongLock。其中,可以允许有多个操作/线程同时分别持有该锁的多个弱锁,但是只允许一个操作/线程持有该锁的强锁,不允许该锁的弱锁和强锁同时被持有。持有弱锁或强锁的操作可以对该堆栈进行操作,操作完成之后,释放其持有的锁。此外,持有所述该弱锁的多个操作可以并行执行,如图lb、图2b和图4a所示。而持有强锁的一操作对该堆栈进行操作时,其它需要对该堆栈进行的操作将被阻塞。这些被阻塞的操作可以尝试获取锁,如周期性地进行尝试。持有弱锁的操作对该堆栈进行搡作时,其它请求获取强锁的搡作将被阻塞,而其它请求获取弱锁的操作可以继续获得弱锁。同样,这些被阻塞的操作可以尝试获取强锁,如周期性地进行尝试。例3<table>tableseeoriginaldocumentpage11</column></row><table>图lb示意性地示出了已有技术中无锁(Lock-free)实现的方法。无锁的方法的出发点是为了克服基于锁的方法扩展性不好的缺陷。如图lb所示,在无锁的方法中,多个线程bl、b2、b3和b4可以并行执行,从而提高进程或程序的执行效率。无锁方法不但可扩展性好,而且鲁棒性也好,如图2b所示。图2b示意性地示出了已有技术中无锁实现的方法的异常退出的情况。如图2b所示,即使一个线程bl死掉,其它线程b2、b3和b4仍然得以执行。但是,无锁方法的开发却非常困难。无锁方法的线程的算法或执行机制与顺序执行的线程经常完全不同。因此,经常需要证明无锁线程之间的复杂逻辑的正确性。并且,有些操:作采用无锁的方法,其执行效率非常低。根据本发明的一实施例,将无锁的并行执行机制和加锁顺序执行机制结合来进行多线程软件的处理。本领域的技术人员可以理解,可以在硬件上、操作系统中或应用程序中设置锁的保护范围或作用域。如已有技术中,通过设置读锁rLock:ReadLock和写锁wLock:WrUeLock的保护范围或作用域,4吏得持有读锁的操作可以并行执行读取操作,而持有写锁的操作可以排他性地执行其操作。本领域的技术人员可以理解,可以采取与已有技术类似的方法,在硬件上、操作系统中或应用程序中设置弱锁和强锁的保护范围或作用域,使得持有弱锁的多个操作可以并行执行其操作,而持有强锁的一操作排他性地执行其操作。如在上述例3中,通过设置弱锁wLock:WeakLock和强锁sLock:StrongLock的保护范围或作用域,使得持有弱锁的多个操作可以并行地执行其操作,而持有强锁一操作则排他性地执行其操作。在这种情况下,多线程程序或进程的可扩展性、鲁棒性或容易开发性,可以通过进一步的机制来确保。图3示出了根据本发明一实施例的用于数据结构的实例进行操作的方法。在步骤S100,开始该方法。在步骤S110,将对it据结构的一实例的操作划分为可无锁'的才乘4乍(lock—freecapableoperation)和不应无4贞的才喿4乍(lock-freeincapableoperation)。如下文所述,可以采用多种方式将对凄t据结构的一实例的操作划分为可无锁的操作和不应无锁的操作。本领域的技术人员可以理解,该步骤的实施可以由软件的开发工具或程序的执行环境来实施,而独立于其它步骤S120-S160。此外,如上文所述可以程序之中,或程序的^l行环境中(如上文所述的在硬件上、操作系统中或应用程序中)设置锁的作用方式。其中,允许有多个操作/线程同时分别持有第一锁的多个弱锁,只允许一个操作/线程持有第一锁的强锁,不允许第一锁的弱锁和强锁同时^皮持有;其中,持有所述第一锁的弱锁的多个可无锁的操作并行执行。其中,一可无锁的操作所执行的操作可以包括写操作。亦即,根据本发明的一实施例,允许有的可无锁的操作只包括读操作而有的可无锁的操作包括写操作。另,在本发明的上述描述中使用的术语"第一锁"的实质含义是指一锁,使用"第一"是为了指代的需要。如文中使用"该第一锁"指代前述的"第一锁",以避免在相应的上下文中使用"该锁"时不易指明是指代前述的"一锁"还是指代前述的"弱锁"等。在步骤S120,为至少一可无锁的操作请求获取一第一锁的弱锁,以便对该数据结构的所述实例进行操作。如果其它操作已经持有该第一锁的弱锁,则允许该至少一可无锁的操作获取该第一锁的另一弱锁。如果其它操作已经持有该第一锁的强锁,则该至少一可无锁的操作将被阻塞,直至该强锁被释放为止。本领域的技术人员可以理解,根据本发明实施例的锁的使用方法,还可以与其它锁的分配机制相结合,如与根据优先级来分配锁的机制相结合,等等。在步骤S130,响应于该至少一可无锁的操作完成获取弱锁,执行该可无锁的操作对该数据结构的实例进行的操作。根据本发明的一实施例,允许有的可无锁的操作只进行读操作而有的可无锁的操作进行写操作。根据本发明的另一12实施例该方法还可以进一步包括响应于该可无锁的才喿作完成对该数据结构的实例的纟喿作,释放该弱锁。在步骤S140,为一不应无锁的操作请求获取所述第一锁的强锁,以便对该数据结构的所述实例进行操作。如果其它操作已经持有该第一锁的弱锁或强锁,则该不应无锁的操作将被阻塞,直至该弱锁或强锁被释放为止。在步骤150,响应于该不应无锁的操作完成获取该强锁,执行该不应无锁的操作对该数据结构的实例进行的操作。根据本发明的另一实施例该方法还可以进一步包括响应于该不能无锁的操作完成对该数据结构的实例的操作,释放该强锁。在步骤160,该方法结束。本领域的技术人员可以理解,步骤S120-S160本身已经构成了一个完整的技术方案,而直接在相应的具有上述强锁和弱锁的运行环境或工具软件上实施。一数据结构的一实例,是指一种数据结构的具体实施对象。链表是一种常用的数据结构,其它常用的数据结构还包括顺序表、树、图、跳表等等。"链表"是一个链表结构,链表中的每个节点都含有指向下一个节点的指针。数据结构"链表"的操作通常有增加元素,删除元素,查询元素,遍历元素,排序。在本发明的实施例中对一链表的实例list进行举例说明,该list中包括多个元素。根据本发明的一实施例,可以使用强锁和弱锁来保护List类。通过设置弱锁和强锁的保护范围或作用域,使得持有弱锁的多个操作可以并行地执行其操作,而持有强锁一操作则排他性地执行其操作。对于可无锁的操:作add()和remove(),可以使用弱锁以便多个可无锁的操作可以并行执行。对于不应无锁的操作使用一强锁,来排他性地访问List,阻塞其它操作对于List的访问。下面举例说明可无锁的操作和不应无锁的操作。在下述实施例中,操作add是可无锁的操作,操作remove是可无锁的操作,而操作sort是不应无锁的操作。操作add获取针对List的弱锁之后,操作remove依然可以获取针对List的弱锁。因此,操作add和操作remove可以并行执行。操作sort不能与操作add或操作remove并行执行。classIist{privateLockweaklock,stronglock;publicList(){WeakStrongLockwslock=newWeakStrongLock();weaklock=wslock.weaklock();stronglock=wslock.stronglock();义List类,然后privateLockweaklock,stronglock为针对该List类的操作定义一锁。在该程序被初始化时将派生一锁WeakStrongLockwslock=newWeakStrongLock(),该锁包括一个或多个弱锁weaklock=wslock.weaklock()和一个强锁stronglock=wslock.stronglock()。publicvoidadd(Objectobj){try{weaklock.lock();〃dothelock-freeaddJfinally{weaklock.unlock();在上述程序中,将对象obj加入List的操作add,可以由一个或多个原子操作组成。因此,操作add是可无锁的操作。在执行时,首先使用weaklock.lock()请求弱锁。获取弱锁之后,执行可无锁的操作add,将对象obj加入List;执行完成后,weaklock,unlock()释放弱锁。如果该锁的强锁被其它的操作或线程持有,add操作将被阻塞。然后,在该锁的强锁被释放后,该add搡作才能获取所请求的弱锁。publicvoidremove(Objectobj){try{weaklock.lock();〃dothelock-freeremove}fmally{weaklock.unlock();在上述程序中,将对象obj从List删除的操作remove,可以由一个或多个原子操作组成。因此,操作remove是可无锁的操作。在执行时,首先使用weaklock.lock()请求弱锁,获取弱锁之后,执行可无锁的l喿作remove;执行完成后,weaklock.unlock()释放弱锁。如果该锁的强锁;故其它的操作或线程持有,则该remove操作将被阻塞。然后,在该锁的强锁被释放后,该remove操作才能获取所请求的弱锁。但是,如果该锁的一弱锁被其它的操作或线程持有,则该14remove操作可以获取该锁的另一弱锁。publicvoidsort(){try{stronglock.lock();〃dosorting}fmally{stronglock.unlock();在上述程序中,将类List的对象obj排序的操作sort,不能分解为一个或多个原子操作。其所需的原子操作数量将随着List中元素数量变化而变化。因此,操作sort是不应无锁的操作。在执行时,首先使用stronglock.lock()请求强锁,获取强锁之后,执行不应无锁的操作sort;执行完成后,stronglock.unlock()释放强锁。如果该锁的强锁或弱锁被其它的操作或线程持有,则该sort操作将被阻塞。然后,在该锁的强锁或弱锁其它操作或线程被释放后,该sort操作才能获取所请求的强锁。上述图3的方法中,步骤S110将对数据结构的实例的操作划分为可无锁的操作和不应无锁的操作可以采用多种方法来进行。才艮据本发明的一实施例,如果一个操作的无锁算法需要的原子操作的数目是一个常数,则将该纟喿作划分为可无锁的操作;如果一个^喿作的无锁算法需要的原子操作的数目不是一个常数,则将该操作划分为不应无锁的操作。在本发明的进一步实施例中,如果一个操作的无锁算法需要的原子操作的数目是一个常数,并且该常数与数据结构的实例中元素的数目不相关,则将该操作划分为可无锁的操作;如果一个操作的无锁算法需要的原子操作的数目不是一个常数,该数目与数据结构的实例中元素的数目相关,则将该操作划分为不应无锁的操作。其中,可无锁的操作对数据结构的实例的才喿作可以分解为由预定数量的原子操作组成的操作。优选地,可无锁的操作对数据结构的实例的操作可以分解为由l-5个原子操作组成的操作。其中,不应无锁的操作对数据结构的实例的一操作,不能分解为由一个或多个原子操作组成的操作。如上述处理List的例子中,元素的添加#:作只需要一个原子操作,而元素的删除操作只需要一个或两个原子操作。因此,这两种操作可以划分为可无锁的操作。而List的排序操作和数据结构中的元素数目相关,因而属于不应无锁才喿作。再如,在堆栈或出栈(pushorpopinstack)可以划分为可无锁的搮:作;而为图形加边框的操作应划分为不应无锁操:作。在本发明之前的已有技术中,对于基于锁的方法都用锁保护。这样数据结构是安全的,但是可扩展性较低。而如果数据结构中的部分操作是无锁而且是多线程安全的,例如List的add()和remove()方法。而其他操:作不是多线程安全的,如List的sort()方法。这样数据结构的使用将相当受限。程序员使用非线程安全的方法需要非常小心,必须等待直到一个安全的时间,并在这个安全的时间之内调用非线程安全的方法。这种方式需要程序员过多的介入,不管是开发效率还是执行效率都受到影响。根据本发明的另一实施例,如果一个操作需要修改的内存单元的数目是一个常数,则将该操作划分为可无锁的操作;如果一个操作的需要修改的内存单元的数目不是常数,则将该操作划分为不应无锁操作。根据本发明的进一步实施例,可无锁的操作需要修改的内存单元的数目与数据结构中元素的数目不相关,不应无锁才喿作需要修改的内存单元的数目与数据结构的实例中元素数目相关。优选地,可无锁的操作的内存单元访问少于一个字或者一个双字;不应无锁操作的内存单元访问多于一个双字或两个不连续的字。对于上述处理List的例子,元素的添加操作只需要修改原List中的一个指针变量,List的删除操作只需要修改List中一个或两个指针变量。因此,这两种搡作被划分为可无锁的操作。而List的排序操作需要修改的指针数量正比于List中的元素数目,因而属于不应无锁搡作。根据本发明的另一实施例,在单线程执行时,对于同一个数据结构实例的每一个操作,如果以无锁的方式实现时的执行效率,与基于锁的方式实现时的执行效率相差小于预定的值,则将该操作划分为可无锁的操作;否则,将该操作划分为不应无锁的操作。优选地,在单线程执行时,如果对于同一个数据结构实例的每一个#:作,以无锁的方式实现时的执行效率,与基于锁的方式实现时的执行效率相差小于1.5倍,则将该操作划分为可无锁的操作;否则,将该操作划分为不应无锁的操作。对于同一个凝:据结构的每一个操作都可以实现两个版本,一个为无锁实现,令一个为基于锁的实现。在上述处理List的例子中,元素的添加操作和删除操作的效率和基于锁的实现差不多。所以划分为可无锁操作。而List的排序操作的无锁实现相当低效,所以划分为不应无锁操作。此外,为图形加边框的操作,如果采用无锁的方式,效率也非常低。才艮据本发明的另一实施例,在图3所示的方法中,允许有多个操作/线程同时分别持有第一锁的多个弱锁,只允许一个操作/线程持有第一锁的强锁,不允许第一锁的弱锁和强锁同时4皮持有;其中,持有所述第一锁的弱锁的多个可无锁的操作并行执行。其中,图3所示的方法进一步包括响应于该可无锁的操作完成对该数据结构的实例的操作,释放该弱锁;响应于该不能无锁的操作完成对该数据结构的实例的操作,释放该强锁。图4a和图4b示出了根据本发明一实施例的操作执行情况。在图4a中,两个或多个可无锁的才喿作被并行执行,此时,一个或多个不应无锁的操作被阻塞。如图4a中所示的操作add()和remove()等操作被并行执行,此时不应无锁的操作size()等被阻塞。在图4b中,一个或多个不应无锁的操作被顺序执行,此时,其它不应无锁的操作以及可无锁的操作被阻塞。如图4b中所示的操作size()等操作被顺序执行,此时其他不应无锁的操作以及可无锁的操作add()和remove()等被阻塞。在本发明之前的已有技术中,无锁的方法具有多种优点,但是却难以开发。因此,无锁机制经常被用于简单的操作。例如,参见以下采用已有技术对于一数据结构的实例-链表List类一的操作。classList(publicvoidadd(Objectobj);publicvoidremove(Objectobj);publicvoidsort();}将无锁机制用于add()和remove()方法并不难。add()用于增加一元素,publicvoidadd(Objectobj)表示为List类增加一对象元素,并且该List的add可以被其它线程的操作访问。remove()用于删除一元素,publicvoidremove(Objectobj)表示为List类删除一对象元素,并且该List的remove可以被其它线程的操作访问。sort()用于对元素进行排序操作,publicvoidsort()表示将List的对象元素进行排序,并且该List的sort可以被其它线程的操作访问。但是,将无锁机制用于sort()方法就很难。原因数据结构实例List—般包括多个元素。这样,在执行List元素排序操作的过程中,如果其它线程对List的对象元素进行增加或删除操作,将引起冲突。因此,自然的方法是使用锁来保护sort()。这样,重写后的代码如下。classList{publicvoidadd(Objectobj);publicvoidremove(Objectobj);publicsynchronizedvoidsort();publicsynchronizedvoidsort()表示在sort执行时需要力口锁和释放锁(lockunlockpair)的操作。在此,将sort()修改为同步的方法,在执行时,首先尝试获取一锁;在获取锁之后,执行排序操作;在排序操作完成后,释放该锁。这样,在任何时候只有一个线程被允许进入该方法调用sort。但是,上述方法并非正确。如果一个线程进入sort()方法,这时另一个线程使用remove()方法来删除一个节点,sort方法将可能失效。因为,add()方法可能在某个时刻与sort()方法交叉。并且,尽管sort()方法加锁;但是,add是无锁的。这就允许add在任何时刻都可以执行,从而由可能产生冲突。因此,安全的版本将采用如下方式,其中对所有操作采取同步(或加锁)的方式进行。classList{publicsynchronizedvoidadd(Objectobj);publicsynchronizedvoidremove(Objectobj);publicsynchronizedvoidsort();}publicsynchronizedvoidadd(Objectobj)表示在add执行时需要力口锁和释放锁(lockunlockpair)的操作。publicsynchronizedvoidremove(Objectobj)表示在remove执行时需要加锁和释放锁(lockunlockpair)的操作。现在,得到了安全的List。但是,其中的全部三个方法都使用锁来保护。这样,如图1和图2所示,在任何时刻,只允许一个线程进入上述三个方法之一。在图1中,简单操作获取一个互斥锁,并阻止其它操作获取该互斥锁。在图2中,复杂操作获取一个互斥锁,并阻止其它操作获取该互斥锁。这种方式妨碍了软件并行执行。图5a和图5b示出了与本发明实施例相对比根据已有技术的一实施例的操作执行情况。该已有技术采用加锁操作。在图5a中,由于add()需要执行写操作,而并非单纯的读操作,因此,得到锁的操作add()被执行时,其它的操作将被阻塞。在图5b中,由于size()需要执行写操作,而并非单纯的读操作,因此,得到锁的操作size()被执行时,其它的操作将被阻塞。与上述一种对数据结构的实例进行操作的方法相对应,本发明还提供了一种对数据结构的实例进行操作的系统,包括弱锁装置,用于为至少一可无锁的操作请求获取一第一锁的弱锁,以便对该数据结构的所述实例进行操作;可18无锁的操作执行装置,用于响应于该至少一可无锁的操作完成获取弱锁,执行该至少一可无锁的操作对该数据结构的实例进行的操作;强锁装置,用于为一不应无锁的操作请求获取所述第一锁的强锁,以便对该数据结构的所述实例进行操作;以及不应无锁的操作执行装置,用于响应于该不应无锁的操作完成获取该强锁,执行该不应无锁的操作对该数据结构的实例进行的操作。其中,弱锁装置和强锁装置进一步配置为允许有多个操作同时分别持有该第一锁的多个弱锁,只允许一个^J喿作持有该第一锁的强锁,不允许该第一锁的弱锁和强锁同时被持有;可无锁的操作执行装置配置为允许持有该第一锁的弱锁的多个可无锁的操作并行执行。其中,上述系统进一步包括阻塞装置,该阻塞装置配置为响应于执行该不应无锁的操作,阻塞请求该第一锁的强锁的操作;响应于执行该不应无锁的^操作,阻塞请求该第一锁的弱锁的操作或其它请求该第一锁的强锁的才喿作。其中,所述弱锁装置进一步配置为响应于该可无锁的操:作完成对该数据结构的实例的操作,释放该弱锁;所述强锁装置进一步配置为响应于该不能无锁的操作完成对该数据结构的实例的操作,释放该强锁。其中,可无锁的操作所执行的操作可以包括写操作。其中,上述系统进一步包括操作划分装置,用于将对数据结构的一实例的操作划分为可无锁的操作和不应无锁的操作。操作划分装置可以进一步配置为使用根据上文所述的多种方法的一种或多种,将对数据结构的一实例的操作划分为可无锁的操作和不应无锁的操作。与已有技术相比,本发明将基于锁的方法和无锁的方法的并行处理进行整合。如上文所述,无锁的代码并行执行可扩展性好,但是难以编程。与此相反,基于锁的方法可扩展性差,但是却容易理解和编程。当多个可无锁的操作在多个线程中并行执行时,可无锁的操作能够确保原子操作特性和共享变量的一致状态。当一个不应无锁的操作与其它不应无锁操作或可无锁操作需要执行时,用一个强锁来确保原子操作特性和共享变量的一致状态。根据本发明的一个实施例,当只有简单的方法而没有复杂操作执行时,可无锁操作就可以并行执行。可以针对全部数据结构安全地并行执行操作。当复杂方法执行时,仍然可以利用强锁来针对全部数据结构安全地执行线程。可无锁操作不会受到不必要的阻止。本发明还提供了一种存储介质或信号载体,其中包括用于执行根据本发明的方法的指令。以上结合优选法方案对本发明进行了详细的描述,但是可以理解,以上实施例仅用于说明而非限定本发明。本领域的技术人员可以对本发明的所示方案进行修改而不脱离本发明的范围和精神。权利要求1.一种对数据结构的实例进行操作的方法,包括为至少一可无锁的操作请求获取一第一锁的弱锁,以便对该数据结构的所述实例进行操作;响应于该至少一可无锁的操作完成获取弱锁,执行该至少一可无锁的操作对该数据结构的实例进行的操作;为一不应无锁的操作请求获取所述第一锁的强锁,以便对该数据结构的所述实例进行操作;以及响应于该不应无锁的操作完成获取该强锁,执行该不应无锁的操作对该数据结构的实例进行的操作。2.根据权利要求l所述的方法,其中,允许有多个操作同时分别持有该第一锁的多个弱锁,只允许一个操作持有该第一锁的强锁,不允许该第一锁的弱锁和强锁同时被持有;其中,持有该第一锁的弱锁的多个可无锁的操作并行执行。3.根据权利要求2所述的方法,其中进一步包括响应于执行该不应无锁的操作,阻塞请求该第一锁的强锁的操作;响应于执行该不应无锁的操作,阻塞请求该第一锁的弱锁的操作或其它请求该第一锁的强锁的操作。4.根据权利要求l所述的方法,其中进一步包括响应于该可无锁的操作完成对该it据结构的实例的l喿作,释^i亥弱锁;响应于该不能无锁的操作完成对该数据结构的实例的操作,释放该强锁。5.根据权利要求1所述的方法,其中可无锁的操作所执行的操作可以包括写操作。6.根据权利要求l所述的方法,其中进一步包括将对数据结构的一实例的操作划分为可无锁的操作和不应无锁的操作。7.根据权利要求1至6任一项所述的方法,其中,如果一个操作的无锁算法需要的原子操作的数目是一个常数,则将该操作划分为可无锁的操作;如果一个操作的无锁算法需要的原子操作的数目不是一个常数,则将该操作划分为不应无锁的操作。8.根据权利要求7所述的方法,其中,如果一个操作的无锁算法需要的原子才喿作的数目是一个常数,并且该常数与数据结构的实例中元素的数目不相关,则将该操作划分为可无锁的操作;如果一个操作的无锁算法需要的原子操作的数目不是一个常数,该数目与数据结构的实例中元素的数目相关,则将该操作划分为不应无锁的操作。9.根据权利要求7所述的方法,其中,可无锁的操作对数据结构的实例的操作可以分解为由预定数量的原子操作组成的操作。10.根据权利要求7所述的方法,其中,可无锁的操作对数据结构的实例的操作可以分解为由l-5个原子操作组成的操作。11.根据权利要求1至6任一项所述的方法,其中,如果一个操作需要修改的内存单元的数目是一个常数,则将该操作划分为可无锁的操作;如果一个操作的需要修改的内存单元的数目不是常数,则将该操作划分为不应无锁操作。12.根据权利要求11所述的方法,其中,可无锁的操作需要修改的内存单元的数目与数据结构中元素的数目不相关,不应无锁操作需要修改的内存单元的数目与数据结构的实例中元素数目相关。13.根据权利要求11所述的方法,其中,可无锁的操作的内存单元访问少于一个字或者一个双字;不应无锁操作的内存单元访问多于一个双字或两个不连续的字。14.根据权利要求1至6任一项所述的方法,其中,在单线程执行时,对于同一个数据结构实例的每一个操作,如果以无锁的方式实现时的执行效率,与基于锁的方式实现时的执行效率相差小于预定的值,则将该操作划分为可无锁的操作;否则,将该操作划分为不应无锁的操作。15.根据权利要求14所述的方法,其中,在单线程执行时,如果对于同一个数据结构实例的每一个操作,如果以无锁的方式实现时的执行效率,与基于锁的方式实现时的执行效率相差小于1,5倍,则将该操作划分为可无锁的操作;否则,将该操作划分为不应无锁的操作。16.—种对数据结构的实例进行操作的系统,包括弱锁装置,用于为至少一可无锁的操作请求获取一第一锁的弱锁,以便对该数据结构的所述实例进行操作;可无锁的操作执行装置,用于响应于该至少一可无锁的操作完成获取弱锁,执行该至少一可无锁的操作对该数据结构的实例进行的操作;强锁装置,用于为一不应无锁的操作请求获取所述第一锁的强锁,以便对该数据结构的所述实例进行操作;以及不应无锁的操作执行装置,用于响应于该不应无锁的操作完成获取该强锁,执行该不应无锁的操作对该数据结构的实例进行的操作。17.根据权利要求16所述的系统,其中,弱锁装置和强锁装置进一步配置为允许有多个操作同时分别持有该第一锁的多个弱锁,只允许一个操作持有该第一锁的强锁,不允许该第一锁的弱锁和强锁同时被持有;可无锁的操作执行装置进一步配置为允许持有该第一锁的弱锁的多个可无锁的操作并行执行。18.根据权利要求17所述的系统,其中进一步包括阻塞装置,该阻塞装置配置为响应于执行该不应无锁的操作,阻塞请求该第一锁的强锁的操作;响应于执行该不应无锁的操作,阻塞请求该第一锁的弱锁的操作或其它请求该第一锁的强锁的操作。19.根据权利要求16所述的系统,其中所述弱锁装置进一步配置为响应于该可无锁的操作完成对该数据结构的实例的操作,释放该弱锁;所述强锁装置进一步配置为响应于该不能无锁的操作完成对该数据结构的实例的操作,释放该强锁。20.根据权利要求16所述的系统,其中可无锁的操作所执行的操作可以包括写操作。21.根据权利要求16所述的系统,其中进一步包括操作划分装置,用于将对数据结构的一实例的操作划分为可无锁的操作和不应无锁的操作。22.根据权利要求21所述的系统,其中操作划分装置进一步配置为使用根据方法权利要求7-15所述的方法的一种或多种,将对数据结构的一实例的操作划分为可无锁的操作和不应无锁的操作。全文摘要本发明提供了一种对数据结构的实例进行操作的方法和系统。该方法包括为至少一可无锁的操作请求获取一第一锁的弱锁,以便对该数据结构的所述实例进行操作。响应于该至少一可无锁的操作完成获取弱锁,执行该至少一可无锁的操作对该数据结构的实例进行的操作。为一不应无锁的操作请求获取所述第一锁的强锁,以便对该数据结构的所述实例进行操作。响应于该不应无锁的操作完成获取该强锁,执行该不应无锁的操作对该数据结构的实例进行的操作。根据本发明的上述方法和系统可以提高对数据结构的实例进行操作的效率。文档编号G06F9/46GK101685406SQ20081014982公开日2010年3月31日申请日期2008年9月27日优先权日2008年9月27日发明者戴晓君,王远洪,志甘,邱模炯,尧齐申请人:国际商业机器公司
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1