1 / 61

Analysis of Concurrent Software Types for Atomicity

Analysis of Concurrent Software Types for Atomicity. Cormac Flanagan UC Santa Cruz. Stephen N. Freund Williams College Shaz Qadeer Microsoft Research. Race Conditions. class Ref { int i; void inc() { int t; t = i; i = t+1; } } Ref x = new Ref(0); parallel {

leif
Download Presentation

Analysis of Concurrent Software Types for Atomicity

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Analysis of Concurrent SoftwareTypes for Atomicity Cormac Flanagan UC Santa Cruz Stephen N. Freund Williams College Shaz Qadeer Microsoft Research Types for Atomicity

  2. Race Conditions class Ref { int i; void inc() { int t; t = i; i = t+1; } } Ref x = new Ref(0); parallel { x.inc(); // two calls happen x.inc(); // in parallel } assert x.i == 2; A race condition occurs if • two threads access a shared variable at the same time • at least one of those accesses is a write Types for Atomicity

  3. Lock-Based Synchronization class Ref { int i; // guarded by this void inc() { int t; synchronized (this) { t = i; i = t+1; } } } Ref x = new Ref(0); parallel { x.inc(); // two calls happen x.inc(); // in parallel } assert x.i == 2; • Field guarded by a lock • Lock acquired before accessing field • Ensures race freedom Types for Atomicity

  4. Limitations of Race-Freedom class Ref { int i; // guarded by this void inc() { int t; synchronized (this) { t = i; i = t+1; } } } Ref x = new Ref(0); parallel { x.inc(); // two calls happen x.inc(); // in parallel } assert x.i == 2; Ref.inc() • race-free • behaves correctly in a multithreaded context Types for Atomicity

  5. Limitations of Race-Freedom class Ref { int i; void inc() { int t; synchronized (this) { t = i; } synchronized (this) { i = t+1; } } ... } Ref.inc() • race-free • behaves incorrectly in a multithreaded context Race freedom doesnot prevent errors due to unexpected interactions between threads Types for Atomicity

  6. Limitations of Race-Freedom class Ref { int i; void inc() { int t; synchronized (this) { t = i; i = t+1; } } synchronized void read() { return i; } ... } Types for Atomicity

  7. Limitations of Race-Freedom class Ref { int i; void inc() { int t; synchronized (this) { t = i; i = t+1; } } void read() { return i; } ... } Ref.read() • has a race condition • behaves correctly in a multithreaded context Race freedom is not necessary to prevent errors due to unexpected interactions between threads Types for Atomicity

  8. Race-Freedom • Race-freedom is neither necessary nor sufficient to ensure the absence of errors due to unexpected interactions between threads Types for Atomicity

  9. x y acq(this) t=i i=t+1 rel(this) z         acq(this) x t=i y i=t+1 z rel(this)         acq(this) x y t=i i=t+1 z rel(this)         Atomicity • The method inc() is atomic if concurrent threads do not interfere with its behavior • Guarantees that for every execution • there is a serial execution with same behavior Types for Atomicity

  10. Motivations for Atomicity • Stronger property than race freedom Types for Atomicity

  11. Motivations for Atomicity • Stronger property than race freedom • Enables sequential reasoning Types for Atomicity

  12. Sequential Program Execution inc() precond. void inc() { .. .. } postcond. Types for Atomicity

  13. Multithreaded Execution void inc() { .. .. } Types for Atomicity

  14. Multithreaded Execution void inc() { .. .. } Types for Atomicity

  15. Multithreaded Execution Atomicity • guarantees concurrent threads do not interfere with atomic method Types for Atomicity

  16. Motivations for Atomicity • Stronger property than race freedom • Enables sequential reasoning • Simple, powerful correctness property Types for Atomicity

  17. Model Checker   filesystem model Model Construction Model Checking of Software Models Specification for filesystem.c // filesystem.c void create(..) { ... } void unlink(..) { ... } Types for Atomicity

  18. Model Checker   Model Checking of Software Specification for filesystem.c // filesystem.c void create(..) { ... } void unlink(..) { ... } Types for Atomicity

  19. Calvin theorem proving  expressed in terms of  concrete state Experience with Calvin Software Checker Specification for filesystem.c x // filesystem.c void create(..) { ... } void unlink(..) { ... } Types for Atomicity

  20. abstract state Calvin theorem proving  Abstraction Invariant  concrete state Experience with Calvin Software Checker ? Specification for filesystem.c x // filesystem.c void create(..) { ... } void unlink(..) { ... } Types for Atomicity

  21. Experience with Calvin Software Checker /*@ global_invariant (\forall int i; inodeLocks[i] == null ==> 0 <= inodeBlocknos[i] && inodeBlocknos[i] < Daisy.MAXBLOCK) */ //@ requires 0 <= inodenum && inodenum < Daisy.MAXINODE; //@ requires i != null //@ requires DaisyLock.inodeLocks[inodenum] == \tid //@ modifies i.blockno, i.size, i.used, i.inodenum //@ ensures i.blockno == inodeBlocknos[inodenum] //@ ensures i.size == inodeSizes[inodenum] //@ ensures i.used == inodeUsed[inodenum] //@ ensures i.inodenum == inodenum //@ ensures 0 <= i.blockno && i.blockno < Daisy.MAXBLOCK static void readi(long inodenum, Inode i) { i.blockno = Petal.readLong(STARTINODEAREA + (inodenum * Daisy.INODESIZE)); i.size = Petal.readLong(STARTINODEAREA + (inodenum * Daisy.INODESIZE) + 8); i.used = Petal.read(STARTINODEAREA + (inodenum * Daisy.INODESIZE) + 16) == 1; i.inodenum = inodenum; // read the right bytes, put in inode } Types for Atomicity

  22. // filesystem.c void create(..) { ... } void unlink(..) { ... } The Need for Atomicity // filesystem.c void create(..) { ... } void unlink(..) { ... } Sequential case: code inspection & testing mostly ok Types for Atomicity

  23. Atomicity Checker   The Need for Atomicity // filesystem.c void create(..) { ... } void unlink(..) { ... } Sequential case: code inspection & testing ok // filesystem.c atomic void create(..) { ... } atomic void unlink(..) { ... } Types for Atomicity

  24. Motivations for Atomicity • Stronger property than race freedom • Enables sequential reasoning • Simple, powerful correctness property Types for Atomicity

  25. Atomicity • Canonical property • (cmp. serializability, linearizability, ...) • Enables sequential reasoning • simplifies validation of multithreaded code • Matches practice in existing code • most methods (80%+) are atomic • many interfaces described as “thread-safe” • Can verify atomicity statically or dynamically • atomicity violations often indicate errors • leverages Lipton’s theory of reduction Types for Atomicity

  26. acq(this) X t=i i=t+1 Z Y rel(this)         X acq(this) t=i i=t+1 Z Y rel(this)         X acq(this) t=i i=t+1 Z Y rel(this)         Reduction [Lipton 75] acq(this) X t=i i=t+1 Z Y rel(this)         Types for Atomicity

  27. acq(this) x S0 S1 S2 x acq(this) S0 T1 S2 Movers • right-mover • lock acquire Types for Atomicity

  28. z rel(this) S5 S6 S7 rel(this) z S5 T6 S7 Movers • right-mover • lock acquire • left-mover • lock release Types for Atomicity

  29. x r=bal S2 S3 S4 r=bal x S2 T3 S4 r=bal y S2 S3 S4 y r=bal S2 T3 S4 Movers • right-mover • lock acquire • left-mover • lock acquire • both-mover • race-free field access Types for Atomicity

  30. Movers x r=bal y • right-mover • lock acquire • left-mover • lock acquire • both-mover • race-free field access • non-mover (atomic) • access to "racy" fields S1 S2 S3 S4 Types for Atomicity

  31. right: lock acquire left: lock release (both) mover: race-free variable access atomic: conflicting variable access Code Classification acq(this) j=bal bal=j+n rel(this) right mover mover left atomic • composition rules:right; mover = right right; left = atomic right; atomic = atomic atomic; atomic = cmpd Types for Atomicity

  32. Composing Atomicities void deposit(int n) { int j; synchronized(this) { j = bal; } synchronized(this) { bal = j + n; } } acq(this) j=bal rel(this) acq(this) bal=j+n rel(this) right mover left right mover left atomic atomic compound Types for Atomicity

  33. atomic void deposit(int n) { synchronized(this) { right int j = bal; mover bal = j + n; mover } left } atomicvoid depositTwice(int n) { synchronized(this) { deposit(n); atomic deposit(n); atomic } } Conditional Atomicity atomic X Types for Atomicity

  34. Conditional Atomicity if this already held atomic void deposit(int n) { synchronized(this) { right mover int j = bal; mover mover bal = j + n; mover mover } left mover } atomicvoid depositTwice(int n) { synchronized(this) { deposit(n); atomic deposit(n); atomic } } atomic mover Types for Atomicity

  35. Conditional Atomicity (this ? mover : atomic)void deposit(int n) { synchronized(this) { right mover int j = bal; mover mover bal = j + n; mover mover } left mover } atomicvoid depositTwice(int n) { synchronized(this) { deposit(n); (this ? mover : atomic) deposit(n); (this ? mover : atomic) } } Types for Atomicity

  36. Conditional Atomicity Details • In conditional atomicity (x?b1:b2), x must be a lock expression (ie, constant) • Composition rulesa ; (x?b1:b2) = x ? (a;b1) : (a;b2) Types for Atomicity

  37. java.lang.StringBuffer /** ... used by the compiler to implement the binary string concatenation operator ... String buffers are safe for use by multiple threads. The methods are synchronized so that all the operations on any particular instance behave as if they occur in some serial order that is consistent with the order of the method calls made by each of the individual threads involved. */ FALSE public atomic class StringBuffer { ... } Types for Atomicity

  38. sb.length() acquires the lock on sb, gets the length, and releases lock use of stale len may yield StringIndexOutOfBoundsException inside getChars(...) java.lang.StringBuffer is not Atomic! public atomic StringBuffer { private int count guarded_by this; public synchronized int length() { return count; } public synchronized void getChars(...) { ... } public synchronized void append(StringBuffer sb){ int len = sb.length(); ... ... sb.getChars(...,len,...); ... } } A A A A C other threads can change sb • append(...) is not atomic Types for Atomicity

  39. java.lang.Vector interface Collection { atomic int length(); atomic void toArray(Object a[]); } class Vector { int count; Object data[]; atomic Vector(Collection c) { count = c.length(); atomic data = new Object[count]; mover ... c.toArray(data); atomic } } X compound Types for Atomicity

  40. Atomicity Inference Types for Atomicity

  41. Bohr • Type inference for atomicity • finds smallest atomicity for each method Bohr Unannotated Java Program Rcc/Sat Program with Atomicity Annotations atomicity inference Atomicity Warnings Types for Atomicity

  42. Atomicity Inference Program w/ Locking Annotations class A<ghost x> { int f guarded_by this; int g guarded_by x; void m() {...} } Atomicity Constraints Constraint Solver Program w/ Atomicity Annotations class A<ghost x> { int f guarded_by this; int g guarded_by x; atomicvoid m() {...} } Constraints Solution Types for Atomicity

  43. Atomicity Details • Partial order of atomicities error compound atomic x?mover:atomic mover const Types for Atomicity

  44. class Account { int bal guarded_by this; 1 void deposit(int n) { synchronized(this) { int j = this.bal; j = this.bal + n; } } } class Bank { 2 void double(final Account c) { synchronized(c) { int x = c.bal; c.deposit(x); } } } Add atomicityvariables Types for Atomicity

  45. Generate constraints over atomicity variabless ≤i Find assignment A class Account { int bal guarded_by this; 1 void deposit(int n) { synchronized(this) { int j = this.bal; j = this.bal + n; } } } class Bank { 2 void double(final Account c) { synchronized(c) { int x = c.bal; c.deposit(x); } } } • Atomicity expression • s ::= const | mover | atomic • | cmpd | error • |  • | s1 ; s2 • | x ? s1 : s2 • | S(l, s) | WFA(E, s) Types for Atomicity

  46. S(this, ((const; this?mover:error); (const;this?mover:error))) class Account { int bal guarded_by this; 1 void deposit(int n) { synchronized(this) { int j = this.bal; j = this.bal + n; } } } class Bank { 2 void double(final Account c) { synchronized(c) { int x = c.bal; c.deposit(x); } } } Types for Atomicity

  47. S(this, ((const; this?mover:error); (const; this?mover:error))) class Account { int bal guarded_by this; 1 void deposit(int n) { synchronized(this) { int j = this.bal; j = this.bal + n; } } } class Bank { 2 void double(final Account c) { synchronized(c) { int x = c.bal; c.deposit(x); } } } Types for Atomicity

  48. S(this, ((const; this?mover:error); (const; this?mover:error))) class Account { int bal guarded_by this; 1 void deposit(int n) { synchronized(this) { int j = this.bal; j = this.bal + n; } } } class Bank { final Account c; 2 void double() { synchronized(this.c) { int x = this.c.bal; this.c.deposit(x); } } } S(l,a): atomicity of synchronized(l) { e }where e has atomicity a S(l, mover) = l ? mover : atomic S(l, atomic) = atomic S(l, compound) = compound S(l, l?b1:b2) = S(l,b1) S(l, m?b1:b2) = m ? S(l,b1) : S(l,b2) if l  m Types for Atomicity

  49. S(this, ((const; this?mover:error); (const; this?mover:error)))≤1 class Account { int bal guarded_by this; 1 void deposit(int n) { synchronized(this) { int j = this.bal; j = this.bal + n; } } } class Bank { 2 void double(final Account c) { synchronized(c) { int x = c.bal; c.deposit(x); } } } Types for Atomicity

  50. S(this, ((const; this?mover:error); (const; this?mover:error)))≤1 class Account { int bal guarded_by this; 1 void deposit(int n) { synchronized(this) { int j = this.bal; j = this.bal + n; } } } class Bank { 2 void double(final Account c) { synchronized(c) { int x = c.bal; c.deposit(x); } } } replace this with name of receiver (const; (this?mover:error)[this:=c]) (const;WFA(E, 1[this := this.a])))) Types for Atomicity

More Related