1 polyphonic c# nick benton luca cardelli cédric fournet microsoft research

39
1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

Upload: carlos-wallace

Post on 27-Mar-2015

215 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

1

Polyphonic C#

Nick Benton

Luca Cardelli

Cédric Fournet

Microsoft Research

Page 2: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

2

Asynchrony is where its at

Distribution => concurrency + latency => asynchrony => more concurrency

Message-passing, event-based programming, dataflow models

For programming languages, coordination (orchestration) languages & frameworks, workflow

Page 3: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

3

Language support for concurrency

Make invariants and intentions more apparent (part of the interface)

Good software engineering Allows the compiler much more freedom to

choose different implementations Also helps other tools

Page 4: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

4

.NET today Java-style “monitors” OS shared memory primitives Clunky delegate-based asynchronous calling model Hard to understand, use and get right

Different models at different scales Support for asynchrony all on the caller side – little

help building code to handle messages (must be thread-safe, reactive, and deadlock-free)

Page 5: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

5

Polyphonic C# An extension of the C# language with new

concurrency constructs Based on the join calculus

A foundational process calculus like the -calculus but better suited to asynchronous, distributed systems

A single model which works both for local concurrency (multiple threads on a single machine) distributed concurrency (asynchronous messaging over

LAN or WAN) It is different But it’s also simple – if Mort can do any kind of

concurrency, he can do this

Page 6: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

6

In one slide: Objects have both synchronous and asynchronous methods. Values are passed by ordinary method calls:

If the method is synchronous, the caller blocks until the method returns some result (as usual).

If the method is async, the call completes at once and returns void. A class defines a collection of chords (synchronization patterns),

which define what happens once a particular set of methods have been invoked. One method may appear in several chords. When pending method calls match a pattern, its body runs. If there is no match, the invocations are queued up. If there are several matches, an unspecified pattern is selected. If a pattern containing only async methods fires, the body runs in a

new thread.

Page 7: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

7

A simple buffer

class Buffer {String get() & async put(String s) {

return s;}

}

Page 8: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

8

A simple buffer

class Buffer {String get() & async put(String s) {

return s;}

}

•An ordinary (synchronous) method with no arguments, returning a string

Page 9: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

9

A simple buffer

class Buffer {String get() & async put(String s) {

return s;}

}

•An ordinary (synchronous) method with no arguments, returning a string

•An asynchronous method (hence returning no result), with a string argument

Page 10: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

10

A simple buffer

class Buffer {

String get() & async put(String s) {

return s;

}

}

•An ordinary (synchronous) method with no arguments, returning a string

•An asynchronous method (hence returning no result), with a string argument

•Joined together in a chord

Page 11: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

11

A simple buffer

class Buffer {

String get() & async put(String s) {

return s;

}

}

•Calls to put() return immediately (but are internally queued if there’s no waiting get()).

•Calls to get() block until/unless there’s a matching put()

•When there’s a match the body runs, returning the argument of the put() to the caller of get().

•Exactly which pairs of calls are matched up is unspecified.

Page 12: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

12

A simple buffer

class Buffer {

String get() & async put(String s) {

return s;

}

}•Does example this involve spawning any threads?

•No. Though the calls will usually come from different pre-existing threads.

•So is it thread-safe? You don’t seem to have locked anything…

•Yes. The chord compiles into code which uses locks. (And that doesn’t mean everything is synchronized on the object.)

•Which method gets the returned result?

•The synchronous one. And there can be at most one of those in a chord.

Page 13: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

13

Reader/Writer…using threads and mutexes in Modula 3

An introduction to programming with threads. Andrew D. Birrell, January 1989.

Page 14: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

14

public class ReaderWriter { public void Exclusive() & async Idle() {} public void ReleaseExclusive() { Idle(); }

public void Shared() & async Idle() { S(1); } public void Shared() & async S(int n) { S(n+1); } public void ReleaseShared() & async S(int n) { if (n == 1) Idle(); else S(n-1); }

public ReaderWriter() { Idle(); }}

A single private message represents the state: none Idle() S(1) S(2) S(3) …

Reader/Writer in five chords

Page 15: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

15

Asynchronous requests and responses

Service exposes an async method which takes parameters and somewhere to put the result: a buffer, or a channel, or a delegate

public delegate async IntCB(int v);

public class Service {

public async request(String arg, IntCB callback) {

int result;

// do something interesting…

callback(result);

}

}

Page 16: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

16

Asynchronous requests and responses - Join

class Join2 { void wait(out int i, out int j)& async first(int r1)& async second(int r2) {

i = r1; j = r2; return;}

}// client code:int i,j;Join2 x = new Join2();service1.request(arg1, new IntCB(x.first));service2.request(arg2, new IntCB(x.second));// do something useful// now wait until both results have come backx.wait(out i,out j);// do something with i and j

Page 17: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

17

Asynchronous requests and responses - Selectclass Select {

int wait()& async reply(int r) {

return r;}

}// client code:int i;Select x = new Select();service1.request(arg1, new IntCB(x.reply));service2.request(arg2, new IntCB(x.reply));// do something useful// now wait until one result has come backi = x.wait();// do something with i

Page 18: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

18

Active Objects

public abstract class ActiveObject : MarshalByRefObject {

protected bool done;

abstract protected void processmessage();

public ActiveObject () {

done = false; mainloop(); }

async mainloop() {

while (!done) { processmessage(); }

}

}

Page 19: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

19

…continued

class Stock : ActiveObject {

override protected void processmessage()

& public async bid(BidOffer thebid) {

// process bid messages

}

override protected void processmessage()

& public async register(Client who) {

// process registration requests

}

}

Page 20: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

20

Extending C# with chords

Interesting well-formedness conditions:1. At most one header can have a return type (i.e. be synchronous).2. The inheritance restriction.3. “ref” and “out” parameters cannot appear in async headers.

Classes can declare methods using generalized chord-declarations instead of method-declarations.

chord-declaration ::= method-header [ & method-header ]* body

method-header ::= attributes modifiers [return-type | async] name (parms)

Page 21: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

21

JoCaml allows multiple synchronous methods to be joined, as in the following rendezvous

But in which thread does the body run? In C#, thread identity is “very” observable, since threads are the holders of particular re-entrant locks. So we rule this out in the interests of keeping & commutative. (Of course, it’s still easy to code up an asymmetric rendezvous in Polyphonic C#.)

Why only one synchronous method in a chord?

int f(int x) & int g(int y) {

return y to f;

return x to g;

}

Page 22: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

22

The problem with inheritance

We’ve “half” overridden f Too easy to create deadlock or async leakage

class C {

virtual void f() & virtual async g() {…}

virtual void f() & virtual async h() {…}

}

class D : C {

override async g() { …}

}

void m(C x) { x.g(); x.f();}

m(new D());

Page 23: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

23

The inheritance restriction

Two methods are co-declared if they appear together in a chord declaration.

Whenever a method is overridden,every co-declared method must also be

overridden.

Hence, the compiler rejects patterns such as

public virtual void f() & private async g() {…}

In general, inheritance and concurrency do not mix well.Our restriction is simple; it could be made less restrictive.

Page 24: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

24

Types etc. async is a subtype of void Allow covariant return types on those two:

An async method may override a void one A void delegate may be created from an async method An async method may implement a void method in an

interface async methods are given the [OneWay] attribute,

so remote calls are non-blocking

Page 25: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

25

Implementation Translate Polyphonic C# -> C# Built on Proebsting & Hanson’s lcsc Introduce queues for pending calls (holding blocked threads for

sync methods, arguments for asyncs) Generated code (using brief lock to protect queue state) looks for

matches and then either Enqueues args (async no match) Enqueues thread and blocks (sync no match) Dequeues other args and continues (sync match) Wakes up blocked thread (async match with sync) Spawns new thread (async match all async)

Efficient – bitmasks to look for matches, no PulseAlls,…

Page 26: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

26

Samples

animated dining philosophers web service combinators (Cardelli & Davies) adaptive scheduler (cf. Larus & Parkes), accessing web services (Terraserver), active objects and remoting (stock trader)

Page 27: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

27

Current and future work

Direct syntactic support for timeouts Limited pattern-matching on message

contents Adding joinable transactions with explicit

compensations Behavioural types?

Page 28: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

28

Conclusions A clean, simple, new model for asynchronous

concurrency in C# Declarative, local synchronization Model good for both local and distributed settings Efficiently compiled to queues and automata Easier to express and enforce concurrency invariants Compatible with existing constructs, though they

constrain our design somewhat Minimalist design – pieces to build whatever complex

synchronization behaviours you need Solid foundations Works well in practice

http://research.microsoft.com/~nick/polyphony/

Page 29: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

29

Fairer reader/writer lockclass ReaderWriterFair { ReaderWriter() { idle(); } private int n = 0; // protected by s() or t()

public void Shared() & async idle() { n=1; s(); } public void Shared() & async s() { n++; s(); } public void ReleaseShared() & async s() { if (--n == 0) idle(); else s(); } public void Exclusive() & async idle() {} public void ReleaseExclusive() { idle(); } public void ReleaseShared() & async t() { if (--n == 0) idleExclusive(); else t(); } public void Exclusive() & async s() { t(); wait(); } void wait() & async idleExclusive() {} }

Page 30: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

30

Predictable Demo: Dining Philosophers

eating

eating

waitingto eat

waitingto eat thinking

Page 31: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

31

Code extractclass Room {

public Room (int size) { hasspaces(size); }

public void enter() & private async hasspaces(int n) {

if (n > 1) hasspaces(n-1);

else isfull();

}

public void leave() & private async hasspaces(int n) {

hasspaces(n+1);

}

public void leave() & private async isfull() { hasspaces(1); }

}

Page 32: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

32

A Better Syntax?class ReaderWriter { private async Idle(); // declare asyncs private async S(int n);

public void Exclusive() when Idle() {} public void ReleaseExclusive() { Idle(); }

public void Shared() // syncs can have sequence of when Idle() {S(1);} // “when” patterns involving | when S(int n) {S(n+1);} // asyncs

public void ReleaseShared() when S(int n) { if (n==1) Idle(); else S(n-1); }}

Could even allow when patterns as general statements, though this seems in dubious taste…

Page 33: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

33

Santa Claus problem (Trono, Ben-Ari) Santa sleeps until awakened by either all 9 reindeer or by 3 of

the 10 elves. If woken by reindeer he harnesses them all up, they deliver

presents together, he unharnesses them, they go off on holiday and he goes back to sleep.

If woken by a group of elves, he shows them into his office, consults with them on toy R&D then shows them all out and goes back to sleep.

Surprisingly tricky to avoid bugs such as Santa going off without the reindeer, queue-jumping elves

Trono posed problem and gave incorrect solution using semaphores

Ben-Ari gave a non-trivial solution using Ada primitives and ugly, inefficient and unsatisfactory solution in Java

Page 34: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

34

public class nway { public async produce(int n) & public void

consume() { if (n==1) { alldone(); } else { produce(n-1); } }

public void waitforalldone() & async alldone() { return; }}

Page 35: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

35

class santa { static nway harness = new nway(); static nway unharness = new nway(); static nway roomin = new nway(); static nway roomout = new nway();

static void santalife() { while (true) { waittobewoken(); // get back here when dealt with elves or reindeer } }

static void waittobewoken() & static async elvesready() { roomin.produce(3); roomin.waitforalldone(); elveswaiting(0); // all elves in the room, consult roomout.produce(3); roomout.waitforalldone(); // all elves shown out, go back to bed }

static void waittobewoken() & static async reindeerready() { // similar to elvesready chord }

Page 36: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

36

static async elflife(int elfid) { while (true) { // work elfqueue(); // wait to join group of 3 roomin.consume(); // wait to be shown in // consult with santa roomout.consume(); // wait to be shown out again } }

static void elfqueue() & static async elveswaiting(int e) {

if (e==2) { elvesready(); // last elf in a group so wake santa } else { elveswaiting(e+1); } }

Page 37: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

37

Pattern Matching

async Sell(string item, Client seller)

& async Buy (string item, Client buyer) {

... // match them up

}

Very useful, but hard to compile efficiently

Page 38: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

38

Ordered processing, currently class SequenceProcessor : ActiveObject { private SortedList pending = new SortedList(); private int next = 0;

public async Message(int stamp, string contents) & override protected void ProcessMessage() { if (stamp == next) { DealWith(contents); while (pending.ContainsKey(++next)) { DealWith((string)pending[next]); pending.Remove(next); } } else { pending.Add(stamp,contents); } } ... }

Page 39: 1 Polyphonic C# Nick Benton Luca Cardelli Cédric Fournet Microsoft Research

39

with matching class SequenceProcessor : ActiveObject {

public async Message(int stamp, string contents) & override protected void ProcessMessage() & async waitingfor(int stamp) { DealWith(contents); waitingfor(stamp++); } SequenceProcessor() { waitingfor(0); } ... }