Chair of Software Engineering Concurrent programming is easy Bertrand Meyer Kirkland, WG 2.3, July 2012 You mean he is actually getting ERC money for What this is about SCOOP: a model for bringing concurrent programming under control Not new (goes back to 90s) But in recent years has been patiently refined (PhD theses) and implemented (now part of standard EiffelStudio) And is receiving a new impetus 3 The issue that SCOOP tackles Can we bring concurrent programming to the same level of abstraction and convenience as sequential programming? 4 Two key goals 1. Retain the modeling power of object-oriented programming, in its Eiffel variant with contracts 2. Retain “reasonability” 5 Dijkstra 68 ... [O]ur intellectual powers are rather geared to master static relations and our powers to visualize processes evolving in time are relatively poorly developed. For that reason we should do ... our utmost to shorten the conceptual gap between the static program and the dynamic process, to make the correspondence between the program (spread out in text space) and the process (spread out in time) as trivial as possible. 6 Concurrent programming today Allen Downey: The Little Green Book of Semaphores, greenteapress.com/semaphores/ 7 Reasoning from APIs transfer (source, target: ACCOUNT; amount: INTEGER) -- Transfer amount from source to target. require source balance >= amount do source withdraw (amount) target deposit (amount) ensure source balance = old source balance – amount target balance = old target balance + amount end invariant balance >= 0 Reasoning from APIs transfer (source, target: ACCOUNT; amount: INTEGER) -- Transfer amount from source to target. require source balance >= amount do source withdraw (amount) target deposit (amount) ensure source balance = old source balance – amount target balance = old target balance + amount end Reasoning from APIs if acc1.balance >= 100 then transfer (acc1, acc2, 100) end if acc1.balance >= 100 then transfer (acc1, acc3, 100) end transfer (source, target: ACCOUNT; amount: INTEGER) -- Transfer amount from source to target. require source balance >= amount do source withdraw (amount) target deposit (amount) ensure source balance = old source balance – amount target balance = old target balance + amount end invariant balance >= 0 Example 2: hexapod robot Hind legs have force sensors on feet and retraction limit switches Hexapod locomotion Ganesh Ramanathan, Benjamin Morandi, IROS 2011 Alternating protraction and retraction of tripod pairs Begin protraction only if partner legs are down Depress legs only if partner legs have retracted Begin retraction when partner legs are up Hexapod coordination rules R1: Protraction can start only if partner group on ground R2.1: Protraction starts on completion of retraction R2.2: Retraction starts on completion of protraction R3: Retraction can start only when partner group raised R4: Protraction can end only when partner group retracted Dürr, Schmitz, Cruse: Behavior-based modeling of hexapod locomotion: linking biology & technical application, in Arthropod Structure & Development, 2004 Sequential implementation Multi-threaded implementation Hexapod coordination rules R1: Protraction can start only if partner group on ground R2.1: Protraction starts on completion of retraction R2.2: Retraction starts on completion of protraction R3: Retraction can start only when partner group raised R4: Protraction can end only when partner group retracted Dürr, Schmitz, Cruse: Behavior-based modeling of hexapod locomotion: linking biology & technical application, in Arthropod Structure & Development, 2004 SCOOP version begin_protraction (partner, me: separate LEG_GROUP) require me legs_retracted partner legs_down not partner protraction_pending do tripod lift me set_protraction_pending end 17 The design of SCOOP (and this presentation) To achieve the stated goals, SCOOP makes a number of restrictions on the concurrent programming model This presentation explains these restrictions The goal is not to limit programmers but to enable them to reason about their programs 18 Handling concurrency simply SCOOP narrows down the distinction between sequential & concurrent programming to six properties, studied next: (A) Single vs multiple “processors” (B) Regions (C) Synchronous vs asynchronous calls (D) Semantics of argument passing (E) Semantics of resynchronization (lazy wait) (F) Semantics of preconditions 19 The starting point (A): processors To perform a computation is To apply certain actions To certain objects Using certain processors Actions Objects Processor Sequential: one processor Concurrent: any number of processors 20 What makes an application concurrent? Processor: Thread of control supporting sequential execution of instructions on one or more objects Can be implemented as: Computer CPU Process Thread Actions Objects Processor The SCOOP model is abstract and does not specify the mapping to such actual computational resources 21 Object-oriented programming The key operation is “feature call” x f (args) where x, the target of the call, denotes an object to which the call will apply the feature f Which processor is in charge of executing such a call? 22 (B): Regions All calls targeting a given object will be executed by a single processor The set of objects handled by a given processor is called a region The processor in charge of an object is its handler Reasoning about objects: sequential Only n proofs if n exported routines! {INV and Prer } bodyr {INV and Postr } ___________________________________ {Prer’ } x.r (a) Priming represents actual-formal argument substitution {Postr’ } The concurrent version of this rule will come later! 24 In a concurrent context Only n proofs if n exported routines? Client 1 r1 Client 2 Client 3 r2 r3 No overlapping! {INV and Prer } bodyr {INV and Postr } ___________________________________ {Prer’} x.r (a) {Postr’} Reasonability 25 SCOOP restriction: one handler per object One processor per object: “handler” At most one feature (operation) active on an object at any time Reasonability 26 Regions The notion of handler implies a partitioning of the set of objects: The set of objects handled by a given processor is called a region Handler rule implies one-to-one correspondence between processors and regions An aside: processor collection Alexander Kogtenkov, MSEPT 2012 Processors, like objects, can become unreachable! Object and processor collection is intertwined References Live objects Basic roots LO = s* (BR r (LP)) LP = BP h (LO) Live processors Basic processors Root objects Handler 28 (C) The sequential view: O-O feature calls x.r (a) Client Supplier previous r (x : A) do … end x.r (a) next Processor 29 (C) The concurrent form of call: asynchronous Client previous x.r (a) next Client’s handler Supplier r (x : A) do … end Supplier’s handler 30 The two forms of O-O call To wait or not to wait: If same processor, synchronous If different processor, asynchronous Difference must be captured by syntax: x: T x: separate T -- Potentially different processor Reasonability Fundamental semantic rule: a call x.r (a) Waits (i.e. is synchronous) for non-separate x Does not wait (is asynchronous) for separate x 31 Why potentially separate? separate declaration does not specify processor: only states that the object might be handled by a different processor In class A: x: separate B In class B: y: separate A In some execution the value of x.y might be a reference to an object in the current region (including Current itself) Call vs application With asynchrony we must distinguish between feature call and feature application The execution of x r (...) is the call, and (with x separate) will not wait (the client just logs the call) The execution of r happens later and is called the feature application 33 Consistency rules: avoiding traitors nonsep : T sep : separate T Traitor! nonsep := sep . nonsep p (a) Reasonability Traitor avoidance: Piotr Nienaltowski’s type system for SCOOP 34 (D) Access control policy Since separate calls are asynchronous there is a real danger of confusion Consider: my_stack : separate STACK [T ] … my_stack.put (a) … Instructions not affecting stack… y := my_stack.item Reasonability 35 (D) Access control policy SCOOP requires the target of a separate call to be a formal argument of enclosing routine: some_routine ( my_stack : separate STACK [T ] ) do … my_stack.put (a) … Instructions not affecting stack… y := my_stack.item end Reasonability 36 (D) Separate argument rule The target of a separate call must be an argument of the enclosing routine Separate call: x.f (...) where x is separate 37 (D) Wait rule A routine call guarantees exclusive access to the handlers (the processors) of all separate arguments some_routine (nonsep_a, nonsep_b, sep_c, sep_d, sep_e ) Exclusive access to sep_c, sep_d, sep_e within a_routine Reasonability 38 Dining philosophers in SCOOP (1) class PHILOSOPHER feature live do from getup until over loop think ; eat (left, right) end end eat ( l, r : separate FORK ) -- Eat, having grabbed l and r. do … end end getup do … end over : BOOLEAN 39 Traditional code 40 Dining philosophers in SCOOP (2) class PHILOSOPHER inherit REPEATABLE rename setup as getup redefine step end feature {BUTLER} step do think ; eat (left, right) end end eat (l, r : separate FORK) -- Eat, having grabbed l and r. do … end Reasonability 41 The general notion of process SCOOP integrates inheritance and other O-O techniques with concurrency, seamlessly and without conflicts (“inheritance anomaly”) No need for built-in notion of active object: it is programmed through a library class such as : class REPEATABLE feature setup do end step do end over : BOOLEAN tear_down do end live do from setup until over loop step end tear_down end end 42 end (D) What the wait rule means Beat enemy number one in concurrent world: atomicity violations Data races Illegal interleaving of calls Data races cannot occur in SCOOP Semantics vs implementation Older SCOOP literature says that feature application “waits” until all the separate arguments’ handlers are available This is not necessary! What matters is exclusive access: implementation does not have to wait unless semantically necessary The implementation performs some of these optimizations f (a, b, c : separate T) do No need to wait for something_else a and b until here a r b s No need to wait for c! end 44 (D) Wait rule A routine call guarantees exclusive access to the handlers (the processors) of all separate arguments some_routine (nonsep_a, nonsep_b, sep_c, sep_d, sep_e ) Exclusive access to sep_c, sep_d, sep_e within a_routine 45 (E) Resynchronization: lazy wait (Caromel) How do we resynchronize after asynchronous (separate) call? No explicit mechanism! The client will wait when, and only when, it needs to: x f x g (a) y f … Wait here! value := x.some_query Lazy wait (also known as wait by necessity) Reasonability 46 (E) Synchrony vs asynchrony revisited For a separate target x: x command (...) is asynchronous v := x query (...) is synchronous 47 (F) Contracts What becomes of contracts, in particular preconditions, in a concurrent context? 48 Preconditions as wait conditions if acc1 balance >= 100 then transfer (acc1, acc2, 100) end if acc1 balance >= 100 then transfer (acc1, acc3, 100) end transfer (source, target: separate ACCOUNT; amount: INTEGER) -- Transfer amount from source to target. require source balance >= amount do source withdraw (amount) target deposit (amount) ensure source balance = old source balance – amount target balance = old target balance + amount end (F) Contracts put (b : separate QUEUE [INTEGER ] ; v : INTEGER) -- Store v into buffer b. require not b is_full i>0 do b.put (i ) ensure Precondition becomes wait condition not b is_empty end . . ... put (my_buffer, 10 ) 50 (F) Full synchronization rule A call with separate arguments waits until: The caller can get exclusive access to their processors Preconditions hold “Separate call”: . x f (a) -- where a is separate Reasonability 51 Generalized semantics of preconditions The different semantics is surprising at first: Separate: wait condition Non-separate: correctness condition At a high abstraction level, however, we may consider that Wait semantics always applies in principle Sequentiality is a special case of concurrency Wait semantics boils down to correctness semantics for non-separate preconditions. Smart compiler can detect some cases Other cases detected at run time 52 Reasoning about objects: sequential {INV and Prer } bodyr {INV and Postr } ___________________________________ {Prer’ } x.r (a) {Postr’ } Only n proofs if n exported routines! 53 Refined proof rule (partial correctness) {INV Prer (x)} bodyr {INV Postr (x)} {Prer (a cont)} e.r (a) {Postr (a cont)} Hoare-style sequential reasoning Controlled expressions (known statically as part of the type system) are: Attached (statically known to be non-void) Handled by processor locked in current context 54 Status All of SCOOP as described here implemented Available as part of standard EiffelStudio download Download: www.eiffel.com 55 SCOOP highlights Close connection to O-O modeling Natural use of O-O mechanisms such as inheritance Built-in guarantee of no data races & fairness Removes many concerns from programmer Supports many different forms of concurrency Retains accepted patterns of reasoning about programs Simple to learn and use (e.g. all standard concurrency examples) Reasonability Limitations & current work Model & theory Deadlock detection -- through alias analysis Multiple readers -- pure queries Exceptions Distribution Transactions se.ethz.ch/research/scoop.html Real-time Proofs Implementation & applications Lazy locking Performance More tools (profiling, debugging…) Real-time High-performance computing Large applications 57