acm-header
登录

ACM通信

研究突出了

金发姑娘:一个种族意识的Java运行时


金发姑娘和三只熊

资料来源:R. John Wright Dolls Inc.。

我们介绍了GOLDILOCKS,这是一个Java运行时,它监视程序的执行并抛出DataRaceException当数据竞赛即将发生时。这可以防止发生异常访问,并允许在异常条件导致稍后可能难以诊断的错误之前处理它们。的DataRaceException是一个很有价值的调试工具,并且,如果有合理的计算开销支持,可以成为已部署程序的一个重要安全特性。我们和其他人在种族感知Java运行时上的实验表明DataRaceException可能是一种可行的机制来加强多线程Java程序执行的安全性。

的一个重要好处是DataRaceException在我们的运行时中的执行保证是无竞争的,因此按照Java内存模型顺序一致。这种强大的保证为程序员提供了一种易于使用的、干净的语义,并有助于排除许多与并发相关的可能性,这些可能性是导致错误的原因。支持DataRaceException,我们的运行时结合了新的Goldilocks算法,用于精确的动态种族检测。Goldilocks算法是通用的、直观的,并且可以统一处理不同的同步模式。

回到顶部

1.简介

当两个不同的线程同时对一个共享变量进行两次访问时,即在相同的程序状态下,称为竞态条件发生。等效的定义涉及一个执行,其中两个线程对变量进行冲突的访问,而在这两个访问之间没有执行适当的同步操作。确保竞争自由的一种常用方法是将一个锁与每个共享变量关联,并确保线程在访问共享变量时持有这个锁。一个线程释放锁,下一个线程获取锁,在两个线程之间建立所需的同步。

数据竞争之所以不受欢迎,主要有两个原因。首先,竞态条件通常是更高级别逻辑错误(如原子性违反)的症状。因此,当原子性注释等更高级别的规范不存在时,竞争检测器充当更通用的并发错误检测的代理。其次,竞态条件使某些共享变量访问的结果不确定。由于这个和其他原因,Java内存模型(JMM)10和c++内存模型(c++ MM)2将良好同步的程序定义为其执行不存在竞态条件的程序。对于无种族执行,这些模型保证语义顺序一致;特别是,每次读都确定地返回“最后一次”写的值。这种语义被广泛认为是惟一一个足够简单的模型,可用它编写实用的并发程序。对于包含竞争条件的执行,语义要么是完全未定义的(正如c++ MM的情况一样)2)或者是非常复杂,以至于编写一个具有“良性种族”的有用且正确的程序是一个挑战。

竞态条件的检测和/或消除一直是激烈研究活动的一个领域。本文提出的工作(最初提出在Elmas等。6)对这一领域做出了两个重要贡献。

首先,我们在文献中第一次提出,竞态条件应该是语言级别的异常,就像空指针解引用和索引数组超出其边界一样。Java的GOLDILOCKS运行时提供了一个新的异常,DataRaceException一个在即将执行导致实际竞态条件的访问时抛出。因为不允许发生动态执行,这保证了执行保持顺序一致。

DataRaceException让程序员清楚地注意到种族问题。当捕获到此异常时,建议的操作过程是优雅地终止程序。这是因为,对于活泼的Java程序,JMM允许进行广泛的编译器优化,这使得将程序执行与源代码关联起来变得非常复杂。如果没有捕捉到异常,Goldilocks运行时将终止抛出异常的线程。虽然不推荐,但程序员也可以选择乐观地使用DataRaceException例如,通过重新尝试导致竞争的代码块,希望冲突线程已经执行了必要的同步,以避免在此期间竞争。自从第一篇关于GOLDILOCKS运行时的论文以来,6某些并发错误(尤其是导致顺序一致性违反的错误)应该导致异常的想法已经得到了大量支持,并且已经研究了该想法的几个实现。911

支持DataRaceException,运行时必须包含精确而有效的竞态检测机制。在这种情况下,种族检测中的假阳性是不能容忍的。我们工作的第二个贡献是GOLDILOCKS算法,这是一种用于在运行时检测数据竞争的新颖、精确和通用算法。在《埃尔马斯等人》中,6我们在一个叫做Kaffe的Java虚拟机(JVM)中提出了GOLDILOCKS算法的实现。19我们在基准测试上使用GOLDILOCKS的实验提出了一种新的可能性,即在运行时中部署后的精确竞争检测的开销可能是可以容忍的。自从GOLDILOCKS运行时首次发表以来,精确种族检测的效率已经取得了显著的进展(参见Flanagan和Freund, Pozmiansky和Schuster,714例如),这个想法在今天看来是可行的。

GOLDILOCKS算法基于对happens-before关系的直观的一般表示,作为每个变量的广义锁集(Goldilockset)。在这个术语的传统用法中,共享变量的锁集x在执行的某一点上包含一组锁。线程可以执行无竞争访问x在这一点上,首先获得这个锁集中的一个锁。Goldilockset是锁集的泛化。在Java中,锁和volatile变量是同步对象,获取和释放锁以及对volatile变量的读写都是同步操作。为了反映这一点,在执行的每个点,共享变量的Goldilocksetx可能包含线程id、锁和volatile变量。线程可以执行无竞争访问x如果它的线程id在Goldilockset中,或者它首先获得了Goldilockset中的一个锁,或者读取了Goldilockset中的一个volatile变量。换句话说,Goldilockset表示拥有所有权的线程x和保护访问的同步对象x在这一点上。Goldilockset在执行同步操作时更新。因此,goldilockset是一种紧凑、直观的方法,可以精确地表示before - happens关系。线程局部变量、在执行的不同时刻受不同锁保护的变量,以及基于事件的与条件变量的同步都由GOLDILOCKS统一处理。此外,goldilockset可以很容易地泛化,以处理其他同步原语,如软件事务18并适应于处理Java以外的语言的内存模型,如c++ MM。为了实现这一点,本文(不同于Elmas等。6),我们提出了一个通用内存模型上的GOLDILOCKS,然后展示了如何将算法专门用于JMM。

*1.1.相关工作

动态种族检测:动态数据竞争检测有两种方法,一种基于锁集,另一种基于happens-before关系。橡皮擦16是一个著名的基于锁集的算法,通过强制每个共享变量由唯一锁保护的锁定规则动态检测竞争条件。尽管已有大量论文对Eraser算法进行了改进,以减少误报的数量,但仍有一些情况无法精确处理,例如动态变化的锁集。Cilk程序有精确的锁集算法,3.但是它们不能处理使用volatile变量实现的并发模式,例如barrier同步。

基于happens-before关系的动态数据竞态检测已经有大量的研究47141517使用矢量时钟。12混合动力技术1420.结合锁集和happens-before分析。例如《RaceTrack》20.使用基本的矢量时钟算法来捕获对对象的线程本地访问,从而消除不必要的和不精确的Eraser算法应用。同样,MultiRace14介绍了DJIT+,这是一种矢量时钟算法,具有几种优化以减少访问时的检查数量,包括为读和写保持不同的矢量时钟,并使用锁集算法作为快速路径检查。据我们所知,FASTTRACK,7它是建立在DJIT+基础上的,是文献中性能最好的基于矢量时钟的算法。通过利用一些访问模式,FASTTRACK减少了矢量时钟更新的成本O(1)平均。我们在4.3节中提供了GOLDILOCKS和FASTTRACK算法的定性比较。矢量时钟和GOLDILOCKS都是精确的,但是GOLDILOCKS中的广义锁集提供了在执行的每个点上如何保护共享变量的直观表示。

并发相关的异常:自Elmas等人首次提出以来,6编程平台应该能够保证顺序一致性的思想所有该计划获得了大量支持。马里诺出版社。11露西亚等人。9为平台提供显式的内存模型异常。这两个平台都定义了比JMM和c++ MM更强大但更简单的契约,它们支持支持内存模型异常的高效硬件实现。

回到顶部

2.通用内存模型

在本节中,我们将介绍一个通用内存模型,并将JMM表示为它的一个特例。这个通用模型允许对Java中的各种同步构造进行统一处理。我们还相信,不同级别(例如,硬件级别)和不同语言(例如,c++ MM)的内存模型可以表示为该模型的实例。这允许在这些设置中直接应用GOLDILOCKS。

变量和动作:程序变量分为两类:数据变量(数据)和同步变量(同步).我们使用x,o分别引用数据和同步变量。程序中的线程执行来自以下类别的操作:

  • 数据变量访问:读(T x v)用线t读取当前值v一个数据变量的x,并写上(T x v)用线t写入值vx。
  • 同步操作:当线程使用同步机制进行同步时,线程t执行通知操作,然后由其他线程观察该操作tj.这样的通知-观察对定义了从前一个动作到后一个动作的“同步”边界。我们将作为同步的源和汇的操作分别分类为同步源和汇操作。
  • -同步源动作:同步源(t o)用线t通过写入同步变量来创建与同步的源o。在Java中,锁释放和volatile变量写入都是同步源操作。
  • -同步接收器动作:sync-sink (t o)用线t通过读取同步变量来创建一个与同步的接收器o。在Java中,锁获取和volatile变量读取都是同步接收器操作。

多线程执行:一个执行E由元组E =Tid, Act, Wcacm5311_p.gif

  • Tid执行中涉及的线程的标识符集。每个新分叉的线程都有一个新的唯一id工业贸易署。
  • 行为在此执行中发生的操作集。行为|t执行的动作集是由tisin.gifTid,行为|x(职责。法|o)是对数据变量执行的操作集x(职责。同步变量o).
  • W是映射每次读取(T x v)行为写入(U x v)的行为。W用于建模读与?之间的写-见关系x写到x它看到。在无竞争的、顺序一致的执行中,这是读(T x v).为了得到这个函数W总的来说,我们假设每个变量在进行读操作之前都进行了初始写操作。
  • cacm5311_q.gif程序是按每个线程排序的吗t.对于每个线程tcacm5311_q.gif全部订单结束了吗行为|t并给出发出操作以执行的顺序。这个顺序有时称为观察到的执行顺序。
  • cacm5311_r.gif是每个同步变量的同步顺序吗oisin.gif同步。为每一个oisin.gif同步cacm5311_r.gif全部订单结束了吗行为|o

synchronized - with和Happens-Before:给定一个带有程序和同步命令的执行,我们提取两个额外的命令,称为synchronized -with (cacm5311_s.gif)和happens-before (cacm5311_t.gif)命令。使用这些顺序定义数据竞赛。

同步操作1通过线程t1同步与2通过线程t2,表示1cacm5311_s.gif2,如果1同步源是否位于某个同步变量上o2同步接收器打开了吗o,1cacm5311_r.gif2

之前偏序cacm5311_t.gif关于执行E定义为程序指令的传递闭包cacm5311_q.gif对所有tisin.gifTid与秩序同步cacm5311_s.gif

在本文中,我们只关注格式良好的死刑,10这一方面(i)线程内语义,另一方面(ii)同步变量和操作的语义。此外,格式良好的执行满足数据竞态检测的两个基本要求:

  • 之前的一致性:此属性使用happens-before顺序来限制write-seen关系。例如,对于读操作,cacm5311_t.gifW()不会发生,而且W()不能被另一个写操作覆盖W()cacm5311_t.gifcacm5311_t.gif
  • 该计划的联合命令为所有人tisin.gifTid以及所有变量的同步顺序oisin.gif同步是有效的部分订单。在执行过程中,我们的数据竞争检测算法检查这个部分顺序的线性化,并识别数据访问之间的happens-before边。

顺序一致性:顺序一致性是一种允许程序员使用交错执行模型的属性,在这种模型中,来自不同线程的访问按总顺序交错,每次读取都看到最近写入的值。顺序一致性被广泛认为是惟一一个足够简单的模型,可以用它编写实用的并发程序。形式上,是执行ETid A Wcacm5311_p.gif按顺序一致如果存在总秩序cacm5311_u.gif行为符合下列条件:

  • 对于每个线程tisin.gifTidcacm5311_u.gif尊重节目顺序cacm5311_q.gif,也就是说,cacm5311_q.gifcacm5311_u.gif
  • 每个read = read(x)看到最近的来信xcacm5311_u.gif,即没有其他= write(x如:如此W()cacm5311_u.gifcacm5311_u.gif

数据竞争:调用两个数据变量访问相互冲突的如果它们引用相同的共享数据变量,并且其中至少有一个是写访问。

竞态条件的一个常用定义涉及一个程序状态,在该状态中,两个不同线程同时启用了对共享数据变量的两次冲突访问。为了区别这个定义和其他定义,我们把这个条件称为同时比赛。在大多数动态竞态检测工作中使用的竞态条件的定义是我们所说的a之前的比赛和涉及两个冲突的访问,而不是按照happens before关系排序,即没有被适当的同步操作分隔。对于c++,这两个竞态条件的定义已经被证明是等价的。2这个证明也适用于Java执行。形式上,是执行ETid, Act, Wcacm5311_p.gif.如果有两个冲突的动作,则包含happens-before race,isin.gif行为|x访问数据变量x,这样一来,cacm5311_t.gif也不cacm5311_t.gif成立。相反,执行是种族自由如果对数据变量的所有冲突访问都按happens-before排序。

执行的良好形式保证了如果执行没有竞态条件,那么它在顺序上是一致的。GOLDILOCKS运行时使用这个和DataRaceException保证所有程序(无论是否活泼)的每次并发执行在字节码级别上顺序一致。这并不限制将GOLDILOCKS运行时用作调试工具,因为对于Java和c++内存模型,它已经得到了验证210如果一个程序有一个快速的执行,那么它可以保证至少有一个执行是顺序一致和快速的。因此,只需将注意力限制在仅在顺序一致的执行中寻找种族就足够了。

回到顶部

3.金发姑娘算法

在本节中,我们将描述在执行中检测数据竞争的算法ETid, Act, Wcacm5311_p.gif.为了说明的简单性,我们最初不区分读和写访问。

GOLDILOCKS算法处理中的动作行为一次一个,按顺序。线程之前t中执行操作行动,t通知即将发生的GOLDILOCKS算法。GOLDILOCKS交错和处理来自不同线程的这些通知的顺序用数学方法表示,其中()是-序列中的第一个动作。这种线性顺序,从结构上讲,尊重每个线程的程序顺序和每个同步变量的同步总顺序。b

GOLDILOCKS算法为每个数据变量维护一个“Goldilockset”:一个映射gl这样,对于每个数据变量x,它的Goldlilockset是一个集合gl (x)Tidcup.gif同步。粗略地说,glx的金发姑娘x紧接在处理行动之前(),由()可以访问的线程的idx(ii)同步变量,线程可以对其执行同步接收器访问以获得无竞争访问x。

当GOLDILOCKS处理每个动作时()E,它更新变量的goldilockset。最初是金发姑娘glx)为所有数据变量(包括静态变量)的空。当创建一个新对象时,其所有实例字段的Goldilockset被初始化为空集。在每个操作之后,每个数据变量的Goldilocksetx可能已更新。对于每个数据变量x,三个简单的规则说明了如何做glx)在(之后更新)基于是否()是(1)同步源,(2)同步接收器,或(3)读或写访问x,如程序所示ApplyLocksetRules图2

如果操作()是对变量的同步操作o,我们更新锁集glx)为每个数据变量x数据。如果()是同步源操作,规则1补充道oglx),如果它包含idt当前访问器线程的。直观地说,这表示线程的后续同步接收操作u关于同步变量o将足以u获得不受种族歧视的进入x。这是由规则2形式化的。如果()是一个同步接收器(o)操作,规则2检查同步变量是否o是在glx).如果是这样的话,那么t被添加到金发姑娘集合中。

如果操作()是对数据变量的访问x,规则3检查变量的Goldilocksetglx)以决定该通道是否不分种族。如果glx)为空,则表示x是否有一个到目前为止还没有被访问过的新变量x在这一点上是种族自由的。如果glx)不是空的,只有id在的线程glx)可以执行无种族访问x。如果访问线程的idt不在glx)然后我们扔一个DataRaceExceptionx。否则,访问x没有种族歧视glx)成为单例{t},表示不进行进一步的同步操作,仅t可以访问x以种族自由的方式。

图1显示数据变量的所有权的两种情况x是否从线程转移t到另一个线程tj,并指出在每种情况下金发姑娘集是如何演变的。节目订购(cacm5311_v.gif)和synchronized -with (cacm5311_s.gif)连续动作之间的边如图所示。图1一个说明所有权的直接转移ttj.后访问xt对同步变量执行同步源操作(释放锁)Lx.之后,tj获得所有权x通过对同步变量执行同步接收操作(锁获取)Lx图1 b说明了可传递的所有权转移。线程t而且tj不要在同一个同步变量上进行同步。相反,同步涉及一个同步链——其他线程和同步变量之间的边。t同步与tk通过同步变量o1群以及后来的tk同步与tj通过同步变量o2

规则1和2图2需要更新每个数据变量的锁集。这种算法的简单实现对于操作大堆的程序来说代价太大。在第4节中,我们通过隐式表示goldilockset和惰性应用更新规则,提出了一种实现算法的有效方法。

正确性:下面的定理表达了GOLDILOCKS算法两者兼有的事实声音,即在给定的执行中检测所有实际的种族,并且精确的,即绝不报告虚惊。Java的原始GOLDILOCKS算法的完整证明可以在Elmas等人中找到。5

定理1(正确性)。令E = Tid, Act, W,cacm5311_p.gif是一个格式良好的执行,x是一个数据变量,并且Act上的线性顺序如前所述。设i < j,设(i)和(j)是线程t对x的两次访问和tj在(i < k < j)访问x之间没有其他操作(k),然后tjisin.gifglj(x),即访问(j)被声明为无种族性的金发女孩算法iff (i)cacm5311_t.gif(j)

*3.1.例如:精确的数据竞争检测

在本节中,我们将通过一个示例说明Goldilocks算法,以及goldilockset如何在执行的每个点捕获保护对变量访问的同步机制。在这个例子中,早期的锁集算法会错误地声明一个竞态条件。

考虑如下所示的执行图3其中所有的行动T1首先发生,其次是所有的行动T2然后T3.此示例模拟了一个场景,在该场景中,对象被创建和初始化,然后由T1.这Int对象(简称为o从现在开始)是一个容器对象数据字段(简称为x从现在开始)。的对象o由不同的全局变量(一个而且b)和局部变量(tmp1, tmp2,tmp3)在执行过程中的不同点。被包含的变量x是否受容器对象上的同步保护o,并且在执行期间,锁()保护o而且x取决于变量(一个b)指向o。注意,T2更改容器对象的保护锁o,无需访问x。图3显示应用的GOLDILOCKS更新规则glx),以及的结果值glx).

注意,更新规则允许变量的Goldilockset在执行期间增长。这使它们能够在执行期间使用不同的同步变量表示转移所有权的线程。在本例中,在不访问变量本身的情况下进行所有权转移。例如,在T2完成在图2glx)的值为{T1 La T2 Lb},表示线程可以访问x没有数据竞赛的锁定.然后T3使唯一的保护锁通过获取并访问x。

*3.2.区分读和写访问

中的基本金发姑娘算法图2跟踪变量的任意两次访问之间的happens-before关系x。为了执行竞态检测,我们必须只检查冲突动作之间的happens-before关系,也就是说,pair中至少有一个动作必须是写访问。我们通过跟踪(i)来扩展基本的金发姑娘算法glWx), Goldilockset写的x和(二)glRt x),“Goldilockset的t而且x"对于每个线程t。更新规则ApplyLocksetRules都适应于维持这些金发姑娘集,但本质上与图2.在扩展算法中,只检查当前访问之间的happens-before就足够了x以及最近的访问(按线性顺序)x。如何为Java执行这个扩展可以在Elmas等人中找到。6

*3.3.专门化JMM的Goldilocks

JMM要求这样做所有同步操作按总顺序排序cacm5311_w.gif,而在我们的执行模型中,是一个单独的总顺序cacm5311_r.gif每个同步变量就足够了。

数据变量和操作:在Java中,每个数据变量都是(o d),o是一个对象d是非易失性字段。字节码指令x负载而且xstore访问内存,分别从对象的字段中读取和写入(x取决于字段的类型)。

JMM指定了三种同步机制:监视器、volatile字段和fork/join操作。

监控:在Java中,每个对象(用o)为每个对象提供一个可重入锁o。获取对象的锁o(收购(o)对应于同步接收器操作o,同时释放的锁o(发布(o)对应于上的同步源操作o.同一锁的嵌套获取和释放被视为无操作。在JMM中,每个版本(o)与下一个获取同步(o)运作cacm5311_w.gifo

Volatile变量:每个volatile变量都表示为(o、v),o是一个对象,和v是一个易变场。每个read volread(o、v)从一个易失性变量(o、v),每个写volwrite(o、v)到(o、v)由xload而且xstore字节码指令。虽然volread (o、v)对应一个同步接收器,volwrite(o、v)对应于(上的同步源操作o、v).在JMM中,每个volread之间有一个synchronized -with关系(o、v)和volwrite(o、v)它能看见。

Fork / Join:创建一个具有id的新线程t(叉(t))与线程的第一个动作同步t,表示start(t).线程的最后一个动作t,表示结束(t)与join操作同步t,表示join(t).对于每个头t叉(t)和end(t)对应于(虚构的)同步变量上的同步源操作cacm5311_x.gif,并开始(t)和join(t)对应于同步接收器操作cacm5311_x.gif.JMM为每个线程保证了这一点t,存在一个秩序cacm5311_y.gif以致于:fork(tcacm5311_y.gif开始(tcacm5311_y.gif结束(tcacm5311_y.gif加入(t).

处理其他同步机制:使用上面的锁集更新规则,GOLDILOCKS能够统一处理各种同步方法,如动态更改锁集、对象的永久或临时线程位置、容器保护对象、变量的所有权转移,而无需访问变量(如3.1节中的示例)。此外,GOLDILOCKS还可以处理java中的同步习惯用法。跑龙套。并发包,如信号量和屏障,因为这些原语是使用锁和volatile变量构建的。由wait/notify(All)构造引发的“before - happens”边是通过对wait内部调用的获取和释放操作应用Goldilockset更新规则来计算的。

*3.4.种族检测和顺序一致性

Java和c++内存模型提供了数据竞争自由(DRF)属性。210DRF属性保证如果所有顺序一致的执行节目是不分种族的,然后编译程序只在内存模型允许的任何编译器和硬件优化之后,显示源程序的这些顺序一致的执行。GOLDILOCKS算法通过监视已编译程序的执行来检查竞争,并假设编译器和构建它的运行时(硬件或虚拟机)符合语言和内存模型规范。因此,如果源程序是无竞争的,则编译程序的任何执行都对应于源程序的顺序一致的执行DataRaceException抛出。

如果源程序有竞争,GOLDILOCKS运行时仍然确保编译程序的所有执行将在顺序一致性语义下运行,也就是说,顺序一致性在字节码级别上得到保证。这是通过防止可能导致数据竞争的访问和抛出DataRaceException就在那个入口之前。然而,在动态程序的情况下,JMM允许编译器优化,这会导致执行与原始源代码的行为顺序不一致的行为。在这种情况下,JMM和DRF属性不够强大,无法允许GOLDILOCKS运行时将字节码级别的执行与源程序级别的执行关联起来,这使得调试变得困难。

要将GOLDILOCKS用于调试目的,可以通过禁用编译器优化来解决这个困难。对于部署后使用,更强的内存模型911它能够将编译程序的每次(快速和无快速)执行与源程序的顺序一致的执行联系起来。

回到顶部

4.实现金发女孩

GOLDILOCKS算法有两个已发布的实现,它们都监视Java字节码级别的执行。在这个级别上,每个变量访问或同步操作对应于单个字节码指令,并且每个字节码指令可以与源代码行和/或变量相关联。

第一个GOLDILOCKS实现是由本文的作者在Kaffe实现的,19在Kaffe中,我们将GOLDILOCKS集成到Kaffe运行时引擎的解释模式中。在JVM中实现算法可以快速访问管理内存中对象布局的JVM内部数据结构,并使用JVM内部存在的高效机制,例如快速互斥锁。

GOLDILOCKS的第二个实现是由Flanagan和Freund使用ROADRUNNER动态程序分析工具实现的。8在ROADRUNNER中,GOLDILOCKS是用Java实现的,并在程序加载时通过字节码插装注入。这允许算法从Java编译器优化和即时编译中受益,并且可以移植到任何JVM。Flanagan和Freund表明,对于大多数通用基准,该实现与我们在Kaffe中的实现具有竞争力。7

接下来,我们将介绍最重要的实现特性和优化。在核心算法的基础上描述了该算法的实现图2.Elmas等人对区分读写访问的实现进行了扩展。6

*4.1.goldilockset的隐式表示和懒求

对于具有大量数据变量的程序,显式地为每个数据变量表示goldilockset,并实现GOLDILOCKS算法图2可能有较高的内存和计算成本。我们通过表示goldilockset来避免内存开销隐式地和计算成本的评估金发姑娘集懒洋洋地如下所述。

而不是保持一个单独的金发姑娘glx)为每个变量x,我们代表glx)隐式只要没有访问x发生并在访问发生时临时计算。此时,Goldilockset是一个单例,我们继续隐式表示它,直到下一次访问。为此,我们将同步事件保存在单个全局链表中synchronization-event列表用它来表示而且尾巴指针在图4.这些事件在列表中的顺序与程序的顺序一致cacm5311_t.gif对于每个线程t和同步顺序cacm5311_r.gif对于每个同步变量oc.当线程执行同步操作时,它必须用该事件原子地将相应的事件附加到同步事件列表中。在Kaffe中,我们通过修改Java同步操作的实现来确保这一点。

为了表示glx),每个变量x在程序中与两个比特信息有关的最近访问x:所有者(x)存储最近访问的线程的idx,pos (x)指向何时考虑的列表中最后一个同步事件glx)是最后一次计算。

图4显示指向同步事件列表中的条目的四个变量。图5展示了金发姑娘是如何glx)计算时x访问。

5(一个):每次访问后x一丝不挂t所有者(x)设置为t,pos (x)设置为指向尾巴同步事件列表的。

5 (b):就在访问之前x通过线程tj,暂时,我们代表glx明确)。glx)是初始的{所有者(x)},并通过处理之间的同步事件进行更新pos (x)(用1、……n),尾巴根据规则1和规则2图2.这个过程停止在tj被添加到glx)或最后一个事件(n)已处理。在前一种情况下,根据规则3,没有种族报告图2.在后一种情况下,从开始报告一个比赛tjisin.gifglx)后进行评估。

5 (c):检查完后,所有者(x)设置为tj而且pos (x)设置为尾巴同步事件列表的。

该实现不使用任何额外的线程进行竞态检测。该算法通过被检查程序的仪表化线程以分散的方式执行。对于每个数据变量x,我们使用一个唯一的锁使每个访问的Goldilockset更新和race-free检查具有原子性x并连载所有种族自由检查x

*4.2.性能优化

短路检查:对于一个变量的最后两次访问之间的happens-before边,一个容易计算的充分条件可以减少竞争检测开销。我们利用两个这样的条件,称为短路检查,并在这些检查成功时绕过对同步事件列表的遍历。在本例中,变量的最终Goldilockset由最后访问它的线程的id组成。

我们采用两种恒时短路检查。首先,当对共享变量的最后两次访问是由同一个线程执行时t的程序顺序保证了happens-before关系t。这是通过检查是否所有者(t)是最后一个访问器线程,它与执行当前访问的线程相同。

在第二次短路检查中,我们确定该变量是否x是否在最后两次访问时使用相同的锁进行保护x。为此,我们关联每个变量x一个锁alock (x),它是在最近访问器线程持有的锁中随机选择的。当一个线程t访问x如果alock (x)是由t,那么这个通道是没有种族歧视的。

直接所有权转让:第三种合理但不精确的优化是,在检查之间的同步事件列表部分时,只考虑当前和最后访问线程执行的同步事件的子集pos (x)而且尾巴。这个检查不是固定的时间,但我们发现它经常成功,足以提高金发姑娘开销。

垃圾收集:当同步事件列表的开始部分有与任何变量的Goldilockset计算无关的条目时,将定期对该同步事件列表进行垃圾回收。当列表中的一个条目无法访问时,就会出现这种情况pos (x)对于任何数据变量x,并通过维护每个列表条目的增量引用计数来跟踪。

部分迫切评价:有时同步事件列表变得太长,当事件列表为变量时,不可能对其进行垃圾回收x在执行的早期访问,但之后不使用。我们通过“部分急切”的金发姑娘集评估来解决这个问题。我们移动pos (x)向前走向尾巴到一个新的职位pos ' (x),并对Goldilockset进行部分评估glx)x通过处理事件(例如,运行ApplyLocksetRules在他们之间)pos (x)而且pos (x)。在接下来的访问中求值glx)从存储的Goldilockset开始,而不是从{开始所有者(x)}。

声音静态竞赛分析:竞争检测的运行时开销与检查的数据变量访问和发生的同步事件的数量直接相关。为了减少运行时检查的访问数量,我们在编译时使用静态分析来确定保证不存在竞争的访问。在Kaffe中实现GOLDILOCKS时,我们为此使用了两个静态分析工具:Chord13和RccJava。1

*4.3.Race-detection开销

在最初的GOLDILOCKS工作的时候,矢量时钟算法12是文献中唯一的精确动态种族检测算法。矢量时钟算法,用于执行n线程,需要为每个线程和同步变量一个独立的矢量时钟(VC)大小n并执行On)操作(合并或比较两个VCs),当同步操作或数据访问发生时。在初步研究中,与矢量时钟的直接实现相比,我们发现GOLDILOCKS开销明显更小。6

在《埃尔马斯等人》中,6我们在一组广泛使用的Java基准测试上测量了Kaffe内部的GOLDILOCKS实现的开销。这种实现要求我们以解释(而不是即时编译)模式运行所有程序。我们发现,使用强大的静态分析工具消除了大量的监视,我们能够获得所有基准测试的大约2以内的减速。如果不静态地消除某些开支,管理费用仍然很高;一些基准测试经历了超过15的减速。静态预消除的开销结果是令人鼓舞的,因为它们表明精确的竞争检测是一种实用的调试工具,并且它们表明,通过进一步优化,将支持部署后运行时竞争检测DataRaceDetection可能可行。

后来在FastTrack的工作中,7基于矢量时钟的动态竞争检测器,可以通过对常见情况的优化来避免矢量时钟的最坏情况性能。弗拉纳根和弗洛伊德7比较了一些赛跑检测算法,包括ROADRUNNER中FASTTRACK和Goldilocks的即时编译实现。FASTTRACK的开销比GOLDILOCKS的两个实现都要高得多。FASTTRACK实现的低开销提供了进一步的支持,为已部署程序提供了一个实用的种族感知运行时,支持DataRaceException可以建造。弗拉纳根和弗洛因德对此有报道7额外的短路检查类似于我们上面讨论的检查,大大减少了FASTTRACK的运行时间。大多数检查也可以合并到GOLDILOCKS实现中。

回到顶部

5.结论

我们为Java提供了一个种族感知运行时,它包含了一种新的算法GOLDILOCKS,用于精确的动态种族检测。运行时提供一个DataRaceException,从而确保执行在字节码级别保持顺序一致。使用GOLDILOCKS的实验表明,支持一个DataRaceException可以做得合理。

回到顶部

致谢

我们要感谢Hans Boehm, Cormac Flanagan, Steve Freund和Madan Musuvathi对本文的评论。该研究由位于华盛顿州雷德蒙德的微软研究院软件可靠性研究小组、土耳其科学技术研究委员会(TUBITAK)拨款104E058和土耳其科学院(TUBA)支持。

回到顶部

参考文献

1.Abadi, M, Flanagan, C, Freund, S.N.安全锁定类型:Java静态种族检测。ACM反式。程序。朗。系统。(2006)。

2.Boehm周宏儒。,Adve, S.V. Foundations of the C++ concurrency memory model. In2008年ACM SIGPLAN编程语言设计与实现会议论文集(PLDI 2008)

3.程,G.-I。,Feng, M., Leiserson, C.E., Randall, K.H., Stark, A.F. Detecting data races in Cilk programs that use locks. InACM并行算法和体系结构研讨会(SPAA 1998)。

4.贸易:Java的数据竞争检测。Proc, Intl。计算科学会议。V.亚历山德罗夫、J.唐加拉、B.朱利亚诺、R.雷纳和C.谭主编。(可以2001)。

5.Elmas, T., Qadeer, S., Tasiran, S. Goldilocks:使用锁集有效计算happens-before关系。技术报告MSR-TR-2006163,微软研究院(2006)。

6.Elmas, T., Qadeer, S., Tasiran, S. Goldilocks:一个支持种族和事务的java运行时。在2007年ACM SIGPLAN编程语言设计与实现会议论文集(PLDI 2007)。

7.Flanagan, C, Freund, S.N. FASTTRACK:高效和精确的动态竞赛检测。在2009年ACM SIGPLAN编程语言设计与实现会议论文集(PLDI 2009)。

8.并行程序的ROADRUNNER动态分析框架,在ACM软件工具和工程程序分析研讨会(粘贴2010)。

9.露西亚,B.,塞兹,L.,施特劳斯,K.,卡迪尔,S., Boehm h . j。冲突异常:通过精确的硬件异常来简化并发语言语义。在第37届计算机体系结构国际研讨会论文集(2010年ISCA)。

10.Manson, J., Pugh, W., Adve, S.V. Java内存模型。在第32届ACM SIGPLAN-SIGACT编程语言原理研讨会论文集(POPL 2005)。

11.Marino, D., Singh, A., Millstein, T., Musuvathi, M., Narayanasamy, S. DRFx:用于并发编程语言的一个简单而高效的内存模型。在2010年ACM SIGPLAN编程语言设计与实现会议论文集(PLDI 2010)。

12.分布式系统的虚拟时间和全局状态。在并行与分布式算法国际研讨会论文集(1988)。

13.奈克,艾肯,魏利,J. Java的有效静态种族检测。在2006 ACM SIGPLAN编程语言设计与实现会议论文集(PLDI 2006)。

14.Pozniansky, E, Schuster, A.多种族:多线程c++程序中高效的动态数据种族检测:研究文章。Concurr。第一版。Pract。经验值。(2007)。

15.RecPlay:一个完全集成的实用记录/回放系统。ACM反式。第一版。系统。(1999)。

16.萨维奇,布伦斯,M,纳尔逊,G,索巴尔瓦罗,P,安德森,T.橡皮:多线程程序的动态数据竞争检测器。ACM反式。第一版。系统。(1997)。

17.访问异常的动态检测。在ACM SIGPLAN编程语言设计与实现会议论文集(PLDI 1989)。

18.Shavit, N, Touitou, D.软件事务存储器。在分布式计算原理研讨会(1995)。

19.Wilkinson, T. Kaffe:一个JIT和解释虚拟机来运行Java代码。http://www.transvirtual.com(1998)。

20.Yu Y, Rodeheffer, T, Chen W. RaceTrack:通过自适应跟踪有效检测数据竞争状况。在第20届ACM操作系统原理研讨会论文集(SOSP 2005)。

回到顶部

作者

Tayfun埃尔玛telmas@ku.edu.tr), Koç土耳其伊斯坦布尔大学。

Shaz卡迪尔qadeer@microsoft.com),微软研究院,雷德蒙德,华盛顿州。

Serdar Tasiranstasiran@ku.edu.tr), Koç土耳其伊斯坦布尔大学。

回到顶部

脚注

a.我们定义DataRaceException类的子类RuntimeException类。

b.一个有活力的读可能出现在它所看到的写之前。如果执行中包含一对访问之间的数据竞争,无论选择哪种线性化,GOLDILOCKS都会在其中一个访问上声明数据竞争。

c.对于Java,所有同步操作都有一个总顺序,列表中的条目就是这个顺序。

本文的原始版本发表在ACM SIGPLAN 2007编程语言设计与实现(PLDI)会议论文集2007年6月。

DOI: http://doi.acm.org/10.1145/1839676.1839698

回到顶部

数据

F1图1。转让所有权x,glx).

F2图2。核心锁集更新规则。

F3图3。精确的数据竞争检测示例。

F4图4。同步事件列表。

F5图5。Goldilockset的懒计算glx).

回到顶部


©2010 acm 0001-0782/10/1100 $10.00

允许为个人或课堂使用本作品的全部或部分制作数字或硬拷贝,但不得为盈利或商业利益而复制或分发,且副本在首页上附有本通知和完整的引用。以其他方式复制、重新发布、在服务器上发布或重新分发到列表,需要事先获得特定的许可和/或付费。

数字图书馆是由计算机协会出版的。版权所有©2010 ACM, Inc。


没有找到条目

登录全面访问
忘记密码? »创建ACM Web帐号
文章内容:
Baidu
map