360 likes | 512 Views
Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs. By Cormac Flanagan, Stephen N. Freund 24 th April, 2008 Hong,Shin. Contents. Introduction Multithreaded Programs Formal definition of multithreaded program The standard semantics of execution
E N D
Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs By Cormac Flanagan, Stephen N. Freund 24th April, 2008 Hong,Shin Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Contents • Introduction • Multithreaded Programs • Formal definition of multithreaded program • The standard semantics of execution • The serialized semantics of execution • Atomicity requirements • Dynamic Atomicity Checking • Reduction • Checking atomicity via reduction • Inferring Protecting Locks Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Introduction 1/4 • A race condition occurs when two threads simultaneously access the same data variable, and at least one of the access is a write. • In practice, race conditions are commonly avoided by protecting each data structure with a lock. • Unfortunately, the absence of race condition is not sufficient to ensure the absence of errors due to unexpected interference between threads. Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Introduction 2/4 • Example: java.lang.StringBuffer public final class StringBuffer { public synchronized int length() { … } public synchronized void getChars(int sBegin,int sEnd,char [] dst,int dBegin) { … } public synchronized void delete(int start, int end) { … } public synchronized StringBuffer append(StringBuffer sb) { int len = sb.length() ; ... /* other threads may change sb.length() e.g. other thread invokes sb.delete(…) */ sb.getChars(0, len, value, count) ; ... } } Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Introduction 3/4 StringBuffer A contains “Hello” StringBuffer B contains “World” <Thread 1> <Thread 2> Lock(A.lock) ; Lock(B.lock) ; int len = B.length() ; /* len = 5 */ Unlock(B.lock) ; Lock(B.lock) ; B.delete(4,5) /* B contains “Worl”. B.length() = 4 */ Unlock(B.lock) ; Lock(B.lock) ; B.getChars(0, len, buf, 0) /* Error */ Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Introduction 4/4 • Atomicity • The construction of reliable multithreaded software requires the development and application of more systematic methods for controlling the interference between concurrent threads. • A code block is atomic if for every (arbitrarily interleaved) program execution, there is an equivalent execution with the same overall behavior(result state) where the atomic method is executed serially(the code block’s execution is not interleaved with actions of other threads). • Atomizer • Dynamic analysis for detecting atomicity violations. • For each code block annotated as being atomic, our analysis verifies that an execution of that code block is not affected by and does not interfere with other thread. Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Multithreaded Programs 1/9 • To provide a formal basis for reasoning about interference between threads, formalizing an execution semantics for multithreaded programs is necessary. Threads • A multithreaded program consists of a number of concurrently executing threads. • Each thread has an associated thread identifier t2Tid . Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Multithreaded Programs 2/9 Global store • The threads communicate through a global store ¾, which is shared by all threads. • The global store maps program variable x to value v. • The global store records the state of each lock variable m2Lock. if ¾(m) = t , then the lock m is held by thread t. if ¾(m) = ? , then the lock is not held by any thread. Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Multithreaded Programs 3/9 Local store • Each thread has its own local store ¼ containing data not manipulated by other threads(e.g. program counter of that thread) State • A state Σ = (¾, ¦ ) ¾ : a global store ¦ : a mapping from thread identifiers t to the local store ¦(t) of each thread. • Program execution starts in an initial state Σ0 =(¾0 , ¦0) Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Multithreaded Programs 4/9 • We model the behavior of each thread in a multithreaded program as the transition relation T : Tµ Tid £LocalStore£Operation£LocalStore T ( t, ¼, a, ¼‘) holds if the thread t can take a step from a state with local store ¼, performing the operation a 2 Operation on the global store, yielding a new local store ¼ ‘. a2Operation ::= rd(x, v) | wr(x, v) read(write) a value v from a variable x | acq(m) | rel(m) acquire(release) a lock m | begin | end | ² beginning and end of an atomic block ² is an empty operation Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Multithreaded Programs5/9 Standard Semantics • The relation ¾!at ¾‘ models the effect of an operation a by thread t on the global store ¾. Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Multithreaded Programs 6/9 • The transition relation Σ ! Σ’ performs a single step of an arbitrarily chosen thread. • A transition sequence Σ0!* Σ’ models the arbitrary interleaving of the various threads of a multithreaded program, starting from the initial state Σ0. • Standard semantics: Σ ! Σ’ T(t,¦(t),a,¼‘) ¾!at¾’ (¾, ¦) ! (¾‘ , ¦[t := ¼‘]) Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Multithreaded Programs 7/9 Serialized Semantics • Assume the function A:LocalStore!N indicates the number of atomic blocks that are currently active. A(¦0(t)) = 0 , for 8t2Tid. if T(t, ¼, begin, ¼‘) then A(¼‘)=A(¼)+1. if T(t, ¼, end, ¼‘) then A(¼)>0 and A(¼‘)=A(¼)-1. if T(t, ¼, a, ¼‘) for a {begin, end} then A(¼‘) = A(¼). • The relation A(¦) holds at a state if any thread is inside an atomic block. A(¦) =def9t2Tid.(A(¦(t)) 0). Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Multithreaded Programs 8/9 • The serialization transition relation does not interleave the execution of an atomic block with instructions of concurrent threads. • Serialized semantics: Σ Σ‘ T(t, ¦(t), a, ¼‘) , ¾!at¾‘ , 8ut.A(¦(u))=0 (¾,¦ ) (¾‘, ¦[t:=¼‘]) Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Multithreaded Programs 9/9 Atomicity requirement • For any program execution (¾0, ¦0) !* (¾, ¦) where :A(¦), there should exist an equivalent serialized execution. (¾0,¦0) * (¾, ¦) • Any execution of a correctly synchronized program should satisfy this requirement. Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Dynamic Atomicity Checking 1/14 • The standard semantics is instrumented to detect atomicity requirement violation dynamically. • Lipton’s theory of reduction forms the basis of this approach. • This theory is based on the notion of right-mover and left-mover actions. Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Dynamic Atomicity Checking 2/14 • For any execution where the action b performed by one thread is immediately followed by an action c of a concurrent threads, the action b is a right-mover if the action b and c can be swapped without changing the resulting state. • For any execution where the action c performed by one thread immediately follows an action b of a concurrent thread, an action c is a left-mover if the action b and c can be swapped without changing the resulting state. Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Dynamic Atomicity Checking 3/14 • The lock acquire operation can be moved to the right without changing the resulting state. • A concurrent thread can neither acquire nor release the lock until the thread releases the lock. • Each lock acquire operation is a right-mover. • The lock release operation can be moved to the left without changing the resulting state. • A concurrent thread can neither acquire nor release the lock since the thread acquired the lock. • Each lock release operation is a left-mover. Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Dynamic Atomicity Checking 4/14 • For an access(read or write) to a variable that is shared by multiple threads, (1) if the variable is protected by some lock that is held whenever the variable is accessed, - No other thread can access the variable between the lock acquire and the release of the thread. - Each access to that variable as a both-mover (both right-mover and left-mover) (2) if the variable is not consistently protected by some lock, - Each access to that variable as a non-mover. Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Dynamic Atomicity Checking 5/14 /* shared variable */ int x ; /* protected by lock m */ int y ; /* protected by lock n */ <thread1> <thread2> lock(m); read(x, 0) ; lock(n) ; read(y, 3) ; write(x, 1) ; write(y,0) ; unlock(n) ; unlock(m) ; Left <thread1> <thread2> lock(m); read(x, 0) ; lock(n) ; write(x,1) ; read(y, 3) ; write(y,0) ; unlock(m) ; unlock(n) ; <thread1> <thread2> lock(m); read(x, 0) ; write(x,1) ; unlock(m); lock(n) ; read(y, 3) ; write(y,0) ; unlock(n) ; Right Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Dynamic Atomicity Checking 6/14 • A path through an atomic code block of a thread should contain a sequence of right-movers, followed by at most one non-moverand then a sequence of left-movers. • This path can be reduced to an equivalent serial execution with the same resulting state, where the path is executed without any interleaved actions by other threads. Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Dynamic Atomicity Checking 7/14 Left int x ; /* protected by lock m */ int y ; /* protected by lock n */ int z ; /* not protected by any lock */ <thread1> <thread2> lock(m); read(x, 0) ; lock(n) ; read(y, 3) ; write(z,0) ; read(z, 0) ; write(x, 1) ; write(y,0) ; unlock(n) ; unlock(m) ; <thread1> <thread2> lock(m); read(x, 0) ; lock(n) ; read(y, 3) ; write(z,0) ; read(z, 0) ; read(z,0) ; write(x, 1) ; write(y,0) ; unlock(n) ; unlock(m) ; <thread1> <thread2> lock(m); read(x, 0) ; lock(n) ; read(y, 3) ; write(z,0) ; read(z,0) ; read(z, 0) ; write(x, 1) ; write(y,0) ; unlock(n) ; unlock(m) ; Right Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Dynamic Atomicity Checking 8/14 • Assume the programmer provides a partial function P that maps protected shared variables to associated locks. P : VariableLock if P(x) is undefined, then x is not protected by any lock. • To record whether each thread is in the right-mover part of an atomic block or in the left-mover part , the state space is extended to include an instrumentation store Á : Tid! {InRight, InLeft} Á0(t) = InRight for 8t2Tid Each state is now a triple (¾, Á, ¦) • If A(¦(t)) 0, then the thread t is inside an atomic block. and Á(t) indicates whether the thread is in the right-mover or left-mover. Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Dynamic Atomicity Checking 9/14 • The relation Σ )at updates the instrumentation store whenever thread t performs operation a. Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Dynamic Atomicity Checking 10/14 Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Dynamic Atomicity Checking 11/14 Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Dynamic Atomicity Checking 12/14 Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Dynamic Atomicity Checking 13/14 Instrumented semantics: Σ ) Σ’ and Σ )wrong • Theorem (Equivalence of Semantics) 1.if (¾, Á, ¦) )* (¾‘, Á‘, ¦‘ ), then (¾,¦) !* (¾‘,¦‘ ) 2.if (¾, ¦) !* (¾‘, ¦‘ ) then8Áeither (a) (¾,Á,¦) )*wrong (b) 9Á‘ such that (¾,Á,¦) )* (¾‘, Á‘, ¦‘ ) • Theorem (Instrumented Reduction) if (¾0, Á0, ¦0 ) )* (¾, Á, ¦) and:A(¦) then (¾0 , ¦0 ) * (¾, ¦) Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Dynamic Atomicity Checking 14/14 StringBuffer A contains “Hello” StringBuffer B contains “World” <Thread 1> Lock(A.lock) ; Lock(B.lock) ; int len = B.length() ; Unlock(B.lock) ; Lock(B.lock) ; B.getChars(0, len, buf, 0) Atomic block begins Right-mover Right-mover Both-mover Left-mover Right-mover/* Error */ Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Inferring Protecting Locks 1/3 • The previous semantics relies on the programmer to specify protecting locks for shared variables. • The semantics is extended to infer protecting locks, using Eraser’s Lockset algorithm. • The instrumentation store Á is extended to map each variable x to a set of candidate locks for x. Á : (Tid! {InRight, InLeft}) [ (Variable! 2Lock) Á0(x) = Lock8x2Variable H(t,¾) = {m2Lock | ¾(m) = t } Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Inferring Protecting Locks 2/3 • The relation updates the extended instrumentation store whenever thread t performs operation a on the global store. Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Inferring Protecting Locks 3/3 • Instrumented Semantics 2: and wrong • Theorem (Equivalence of Semantics 2) • Theorem (Instrumented Reduction 2 Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Automated Data Race Detection using CBMC 1/2 • To check every path in a thread, it is necessary to consider the changing of value of a shared variable between releasing and acquiring its corresponding lock. (e.g. Unlock before I/O pattern) /* shared variables */ int A, int B ; Lock m ; Lock n ; <thread1> <thread2> lock(m) ; lock(m) A = 1 ; A = 0 ; unlock(m) ; unlock(m) ; lock(m) ; lock(n) ; if (A == 1 ) B = 1 ; else B = 0 ; unlock(n) ; unlock(m) ; Set Unlock Lock Read B is not consistently protected by any lock Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Automated Data Race Detection using CBMC 2/2 • But in checking the sequence of threads can not detect this data race error. /* shared variables */ int A, int B ; Lock m ; Lock n ; <thread1> lock(m) ; A = 1 ; unlock(m) ; lock(m) ; if (A == 1 ) else B = 0 ; unlock(m) ; <thread2> lock(m) A = 0 ; … Additional code that change the value of A should be inserted here This branch never be taken • Identify what variables are in this pattern in the program • Change the value of the shared variable between unlock and lock Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Further Work • Reduction: A Method of Proving Properties of Parallel Programs, B. Wegbreit • High-Level Data Race, C Artho, K Havelund, A Biere Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs
Reference [1] Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs Cormac Flanagan, Stephen N. Freund, ACM SIGPLAN 2004 Atomizer: A Dynamic Atomicity Checker For Multithreaded Programs