一种基于线程逻辑时钟的事务内存的实现方法

文档序号:1815299 发布日期:2021-11-09 浏览:19次 >En<

阅读说明:本技术 一种基于线程逻辑时钟的事务内存的实现方法 (Method for realizing transactional memory based on thread logic clock ) 是由 王芳 冯丹 刘超杰 邹晓敏 于 2021-07-23 设计创作,主要内容包括:本发明公开了一种基于线程逻辑时钟的事务内存的实现方法,每个线程拥有一个自己的时间戳,时间戳包括线程ID和逻辑时钟,时间戳由时间戳管理器分配和回收;本发明还公开了基于线程逻辑时钟的事务内存的初始化、数据校验、事务提交的流程。本发明允许每个线程拥有自己的逻辑时钟,事务开始执行时读取自己线程的逻辑时钟,事务提交时将自己线程的逻辑时钟加1更新,由此避免了访问全局变量,消除了多个并发事务的读或更新操作所带来的缓存争用。(The invention discloses a method for realizing a transactional memory based on a thread logic clock, wherein each thread has a timestamp, the timestamp comprises a thread ID and a logic clock, and the timestamp is distributed and recovered by a timestamp manager; the invention also discloses the processes of initialization, data verification and transaction submission of the transaction memory based on the thread logic clock. The invention allows each thread to have its own logic clock, reads the logic clock of its own thread when the transaction starts to execute, and adds 1 to update the logic clock of its own thread when the transaction is submitted, thereby avoiding accessing global variables and eliminating cache contention caused by read or update operations of multiple concurrent transactions.)

一种基于线程逻辑时钟的事务内存的实现方法

技术领域

本发明属于计算机数据存储领域,更具体地,涉及一种基于线程逻辑时钟的事务内存的实现方法。

背景技术

目前,大多数的事务内存都是基于时间戳实现的:每个事务由一个线程执行,每个线程可执行多个事务,但是同一时间只能执行一个事务。事务内存需要维护一个全局逻辑时钟,全局逻辑时钟通常使用一个全局的整型变量来实现。全局逻辑时钟为每个线程分配一个时间戳,每次分配时将当前的全局逻辑时钟值加1赋值给线程的时间戳,并使用上述加1后的值更新全局逻辑时钟。事务内存利用时间戳来保证线程并发的一致性,为了保证多线程并发的正确性,可以使用锁来对其进行保护。

事务对内存中的数据进行读或写操作,内存中的数据为原始数据,每个原始数据都有一个自己的时间戳,原始数据的时间戳为逻辑时钟。

事务使用读集合(read-set)记录事务读过的原始数据,使用写集合(write-set)记录事务写过的原始数据,读集合包括原始数据的地址和时间戳,写集合包括原始数据的地址和原始数据修改后的值,当事务创建时,事务的读集合和写集合为空集。

事务分为两种:一种是更新事务,其会写某些数据;另一种是只读事务,其不会写任何数据。

基于时间戳的事务内存的更新事务流程包括如下步骤:

第一步,事务初始化操作:获取全局逻辑时钟当前的值并记录在名为起始时钟的局部变量中,这里用sc(start clock)表示该值,sc的作用范围仅在本事务内,sc将在后面用于校验数据的一致性。

第二步,开始读或写数据。在读或写数据时需要校验被读取的原始数据是否是一致的,这是因为其他更新事务可能正在修改该原始数据,如果不进行校验,会读取到未提交的修改。数据校验的流程为:当原始数据的时间戳小于等于sc且该原始数据对应的锁没有被其他线程获得时,说明最近的更新该原始数据的事务在此事务开始前已经完成,并且目前没有其他事务去更新它,此时认为数据是一致的,数据校验通过,事务继续执行,否则终止该事务的执行并进行重试。

第三步,对于写操作,对原始数据加锁,并将原始数据修改后的值和原始数据的地址放入写集合;对于读操作,在读集合中记录原始数据的地址和时间戳。

第四步,事务提交操作,具体流程为:首先校验读集合,这是因为之前读取的值可能在事务的执行过程中又被修改。校验读集合的方法为:校验读集合中所有的数据的时间戳是否大于或者等于对应的原始数据的时间戳,如果小于,终止该事务并进行重试;如果大于或者等于,则校验成功,将写集合中对数据的修改写回到原始数据中;将全局逻辑时钟的值加1后作为提交时间戳(commit timestamp,ct),使用提交时间戳更新全局逻辑时钟,并把被执行写操作的原始数据的时间戳更新为ct。最后,释放该事务获得的锁,整个更新事务完成。

只读事务的执行流程比较简单,包括如下步骤:第一步和更新事务相同,即获取全局逻辑时钟当前的值sc。第二步读取原始数据并进行数据校验,数据校验的流程与更新事务相同,如果校验通过,在读集合中记录原始数据的地址和时间戳,事务继续执行;否则终止该事务并重试。只读事务由于不会对原始数据产生任何修改,因此不需要进行任何提交。

从执行流程中可以发现,基于时间戳的事务内存有两个地方需要对全局逻辑时钟进行操作:(1)事务初始化操作时,读取当前全局逻辑时钟的值;(2)事务提交操作时,对全局逻辑时钟的值加1更新。其中第一处是对全局逻辑时钟的读操作,第二处是对全局逻辑时钟的更新操作。当并发事务较多时,多个事务会频繁读或更新全局逻辑时钟,由此带来了大量的缓存争用,进而成为整个系统的性能瓶颈。

发明内容

针对现有技术的以上缺陷,本发明的目的在于设计一种线程逻辑时钟,旨在解决了现有的事务内存由于使用全局逻辑时钟导致在多线程环境中带来大量缓存争用的技术问题。

为实现上述目的,本发明提供了一种基于线程逻辑时钟的事务内存的实现方法,每个线程拥有一个自己的时间戳,时间戳包括线程ID和逻辑时钟,事务初始化操作时,读取自己线程的逻辑时钟并记录下来;事务提交操作时,将自己线程的逻辑时钟加1更新。

现有技术中事务初始化操作时需要读取当前的全局逻辑时钟,全局逻辑时钟由一个全局变量来实现,事务提交操作时需要对全局逻辑时钟加1更新,多个并发事务读或更新全局逻辑时钟带来了大量的缓存争用。本发明不再使用全局逻辑时钟,而是允许每个线程拥有自己的逻辑时钟,事务初始化操作时读取自己线程的逻辑时钟,事务提交操作时将自己线程的逻辑时钟加1更新,由此避免了访问全局变量,消除了多个并发事务的读或更新操作所带来的缓存争用。

优选地,时间戳的大小是64比特,其中前n比特存储线程ID,后64-n比特用来存储逻辑时钟,n=log2t,t为当前运行的线程数量。

优选地,事务内存实现了一个时间戳管理器,当新线程被创建时,在时间戳管理器中分配一个时间戳给新线程;当线程被销毁时,回收该线程的时间戳。

本发明不再使用系统提供的线程ID,而是使用时间戳管理器为线程分配线程ID和逻辑时钟值。当使用系统提供的线程ID时,线程运行结束后线程ID并不会被立即回收,而是等达到最大值的时候再回收,随着线程的创建与销毁,系统中需要维护大量的线程ID,这会增加存储开销。本发明中由于线程ID的分配与回收仅仅在线程创建和销毁时被调用,系统中不需要维护大量的线程ID,因此不会增加存储开销。

优选地,时间戳管理器从0开始分配线程ID,对应的逻辑时钟也为0,线程ID和逻辑时钟都是加1递增。

优选地,时间戳管理器使用锁来保证时间戳的并发分配。

优选地,被回收的时间戳可以再次分配使用

优选地,每个原始数据都有一个自己的时间戳,原始数据的时间戳包括线程ID和逻辑时钟,原始数据为被事务读或写的内存中的数据。

优选地,事务开始执行时,初始化操作为:事务为自己的线程创建一个起始时钟,起始时钟的作用范围仅在事务内部;事务读取自己线程的逻辑时钟赋值给起始时钟。

优选地,事务执行的过程中,需要进行数据校验,包括如下步骤:

s1:所述事务从原始数据的时间戳中获取线程ID,如果所述线程ID并非是所述事务自己的线程ID,则为所述线程ID创建一个值为0的起始时钟,所述起始时钟的作用范围仅在所述事务内部。

s2:如果所述原始数据的逻辑时钟小于等于所述线程ID对应的起始时钟,则所述事务继续执行;

s3:如果所述原始数据的逻辑时钟大于所述线程ID对应的起始时钟,则校验所述事务的读集合中所有的数据的时间戳是否大于或者等于其对应的原始数据的时间戳,如果大于或者等于,则使用所述原始数据的逻辑时钟更新所述线程ID对应的起始时钟,所述事务继续执行;否则终止事务,并重做事务。

优选地,事务的提交操作包括如下步骤:

s1:校验所述事务的读集合中所有的数据的时间戳是否大于或者等于对应的原始数据的时间戳;

s2:如果大于等于,将所述事务的写集合里的原始数据修改后的值同步到原始数据中;将所述事务的线程的逻辑时钟加1后作为提交时间戳,使用所述提交时间戳更新所述事务的线程的时间戳,所述提交时间戳会被写入到被执行写操作的原始数据的时间戳中;最后,释放所述事务获得的锁,提交事务;

s3:如果小于,终止事务并重做事务。

通过本发明所构思的以上技术方案,与现有技术相比,由于允许每个线程拥有自己的逻辑时钟,在进行事务初始化操作和事务提交操作时都是对自己线程的逻辑时钟进行操作,由此避免了访问全局变量,能够取得消除多个并发事务的读或更新操作所带来的缓存争用的有益效果。

附图说明

图1是本发明所提供的线程时间戳的结构图,其中,n=log2t,t为当前运行的线程数量;

图2是本发明实施例所提供的数据校验操作的流程图;

图3是本发明实施例所提供的事务提交操作的流程图。

具体实施方式

为了使本发明的目的、技术方案及优点更加清楚明白,以下结合附图及实施例,对本发明进行进一步详细说明。应当理解,此处所描述的具体实施例仅仅用以解释本发明,并不用于限定本发明。

基于线程逻辑时钟的更新事务和只读事务的执行过程与现有技术相比,只有事务初始化操作、数据校验、事务提交操作的流程不同,其他操作是相同的;事务的读集合和写集合的定义也与现有技术相同。

本实施例是一个基于线程逻辑时钟的更新事务执行过程的例子,该事务所作的操作是先读取数据a再修改数据b。

如图1,时间戳由线程ID和逻辑时钟组成,记为(线程ID,逻辑时钟)。因为每个线程的线程ID都不相同,所以每个线程的时间戳都是独一无二的。

事务开始之前数据的状态为,数据a的时间戳为(1,5),说明a最近一次是被线程1修改的,且当时线程1的时钟值为5;数据b的时间戳为(2,4),说明b最近一次是被线程2修改的,且当时线程2的时钟值为4。该事务由线程1执行,线程1的时间戳为(1,7)。

线程1进行事务初始化操作:为线程1创建一个起始时钟,起始时钟的作用范围仅在事务内部;事务读取线程1的逻辑时钟7赋值给该起始时钟,记为sc(线程ID)=起始时钟,即sc(1)=7。

现有技术中事务初始化操作时需要读取当前的全局逻辑时钟。本发明中事务初始化操作时读取自己线程的逻辑时钟,由此避免了访问全局变量,消除了多个并发事务的读操作所带来的缓存争用。

线程1读取数据a:首先进行数据校验,如图2,数据校验流程如下:

(1)线程1从数据a的时间戳(1,5)中获取线程ID为1,该线程ID与事务自己的线程ID相同;

(2)对比数据a的逻辑时钟和线程1的起始时钟的大小,数据a的逻辑时钟5小于线程1的起始时钟7,说明在事务开始后,数据a没有被其他事务修改过,数据校验通过,数据是一致的,事务继续执行。

线程1读取a的数据,将数据a的地址和时间戳(1,5)放入读集合中。

线程1修改数据b:首先进行数据校验,如图2,数据校验流程如下:

(1)线程1从数据b的时间戳(2,4)中获取线程ID为2,该线程ID与事务自己的线程ID不相同,事务为线程2创建一个值为0的起始时钟,记为sc(2)=0,该起始时钟的作用范围仅在本事务内部。

现有技术和本发明均使用起始时钟进行数据校验,现有技术中的起始时钟通过读取全局逻辑时钟而获得,本发明中,事务读取自己线程的逻辑时钟赋值给自己线程的起始时钟,将其他线程的起始时钟设置为0。这是因为,如果事务读取其他线程的逻辑时钟赋值给其他线程的起始时钟,当多个事务并发执行时,多个事务的读操作会带来大量的缓存争用开销,这是因为根据缓存一致性协议,当一个线程读取一个其他线程的逻辑时钟后,便在自己的缓存里增加了该逻辑时钟的一个副本,如果有其他线程对该逻辑时钟进行了修改,那么这个线程里的副本便需要被同步,通常的同步做法是置为无效状态。当并发执行的事务数量增加,这种同步的操作便会带来大量的开销。

当更新事务在提交时,会将提交时间戳写入到被写的数据的时间戳中。因此,在数据的时间戳属性中存储着线程的逻辑时钟的历史值。这里使用了历史值,是因为并不是所有数据的时间戳都存储着逻辑时钟的最新值,根据线程逻辑时钟的执行流程,只有少量数据存储着最新值,大部分数据存储的是逻辑时钟的旧值,即比真正的逻辑时钟要小。使用这些较旧的逻辑时钟来检验数据的一致性是完全可行的,这是因为时钟值总是单调递增的,如果事务开始后,其访问的数据被其他更新事务修改,那么被修改后的数据,其时间戳一定大于任何一个之前产生的旧的时间戳。所以使用较旧的比真正的逻辑时钟要小的逻辑时钟是可以用来校验数据的一致性的。因此本发明中,事务将其他线程的起始时钟设置为0,是可以用来校验数据的一致性的,还可以避免多个事务读取其他线程的逻辑时钟所带来的大量的缓存争用。

(2)对比数据b的逻辑时钟和线程2的起始时钟的大小,数据b的逻辑时钟4大于线程2的起始时钟0,数据校验不通过,但是事实上事务开始之后,数据b并没有被其他事务修改过,此时如果终止事务,会带来较高的事务终止率。如果在事务终止之前,该事务所访问的数据在事务开始后没有被其他线程修改,那么将线程2的起始时钟修改为一个更大的值仍然能够保证数据的一致性,同时避免了事务终止的发生,事务可以继续执行。通过对读集合进行校验可以判断该事务所访问的数据在事务开始后没有被其他线程修改。由于被写的数据在访问时都会获取锁,所以一定不会被其他事务修改,因此不需要校验写集合中的数据,只需要对读集合进行校验。

(3)读集合中数据a的时间戳为(1,5),原始数据a的时间戳为(1,5),两者一致,校验通过;使用原始数据b的逻辑时钟4更新线程2对应的起始时钟,即sc(2)=4,线程2的起始时钟被修改为一个更大的值;事务继续执行。

线程1对原始数据b加锁,并将原始数据b的地址和修改后的值放入写集合。

线程1提交该事务:如图3,提交事务的流程如下:

(1)校验读集合中所有的数据的时间戳是否大于或者等于对应的原始数据的时间戳,读集合中数据a的时间戳为(1,5),原始数据a的时间戳为(1,5),两者一致,校验通过。

(2)将写集合中对数据b的修改写回到原始数据b中;将线程1的逻辑时钟7加1后作为提交时间戳,使用提交时间戳(1,8)更新线程1的时间戳,并把原始数据b的时间戳更新为提交时间戳(1,8)。最后,释放该事务获得的锁,整个更新事务完成。

现有技术中事务提交操作时需要对全局逻辑时钟加1更新,本发明中事务提交操作时将自己线程的逻辑时钟加1更新,由此避免了多个并发事务的更新操作所带来的缓存争用。

本领域的技术人员容易理解,以上所述仅为本发明的较佳实施例而已,并不用以限制本发明,凡在本发明的精神和原则之内所作的任何修改、等同替换和改进等,均应包含在本发明的保护范围。

10页详细技术资料下载
上一篇:一种医用注射器针头装配设备
下一篇:延迟控制电路及方法

网友询问留言

已有0条留言

还没有人留言评论。精彩留言会获得点赞!

精彩留言,会给你点赞!