430 likes | 625 Views
Modern Concurrency Abstractions for C#. Advanced Software Tools Seminar December, 2004. presented by: Guy Gueta. Agenda. Concurrency Concurrency and Languages Asynchronous Programming C# and .NET Polyphonic C# Examples Performance. Concurrency.
E N D
Modern Concurrency Abstractions for C# Advanced Software Tools Seminar December, 2004 presented by: Guy Gueta
Agenda • Concurrency • Concurrency and Languages • Asynchronous Programming • C# and .NET • Polyphonic C# • Examples • Performance
Concurrency • Concurrency is widely used in modern code • It is very difficult to write/debug concurrent programs
Concurrency • Can affect the ability to invoke libraries • strtok(….) / Rand() & SRand(….) • Can significantly affect the meaning of virtually every construct in the language • X++ ; • X = Y ; • Most popular programming languages treat concurrency not as a language feature, but as a collection of external libraries
Language Features / Libraries • Many features can be provided either as language features or as libraries • Memory management • Exceptions • Locks • The compiler can analyze language features • Can produce better code (e.g. local new) • Can warn programmers of potential and actual problems. • Polyphonic C#
Example: Monitor • The concept of monitors [Hoare 1974] • The general notion of monitors has become very popular public synchronized void Add(int v) { // body } public synchronized int Get(int v) { // body } wait()/notify()
Asynchronous Programming • Asynchronous events and message passing are increasingly used at all levels of software systems • e.g. Distributed Applications/components, GUI, Device Drivers • Many asynchronous messages should be handled concurrently. Many threads are used to handle them • Polyphonic C#
C# and .NET • Modern, type-safe, object-oriented programming language • Very similar to Java • C# programs run on top of the .NET Framework, which includes a multi-language execution engine and a rich collection of class libraries. • .NET IL
JAVA public class Point { protected int x, y; public Point() { setPoint( 0, 0 ); } public Point( int a, int b ) { setPoint( a, b ); } public void setPoint( int a, int b ) { x = a; y = b; } public int getX() { return x; } public int getY() { return y; } } C# public class Point { protected int x, y; public Point() { setPoint( 0, 0 ); } public Point( int a, int b ) { setPoint( a, b ); } public void setPoint( int a, int b ) { x = a; y = b; } public int getX() { return x; } public int getY() { return y; } }
Concurrency in .NET • Threads • Sync. Event (Semaphore, Mutex) • Reader/writer lock • Asynchronous programming model based on delegates • lock (C#)
Polyphonic C# Adds just two new concepts: asynchronous methodsand chords
Synchronous Methods • Regular C# methods • The caller makes no progress until the callee completes
Asynchronous Method • Any call to it is guaranteed to complete essentially immediately • Never returns a result (or throws an exception) • calling it is much like sending a message, or posting an event • declared by using the async keyword instead of void public asyncpostEvent(EventInfo data) { // large method body } • Usually defined using chords – do not necessarily require new threads
Chord A set of method declarations separated by ‘&’ And a body. public string Foo1()& public async Foo2(string s1)& public async Foo3(string s2)& private async Foo4(string s3) { // Body } At most one method may be synchronous. Return Value type = Synchronous method type
Chord public asyncFoo1()& public async Foo2(string s1)& public async Foo3(string s2)& private async Foo4(string s3) { ….. } public string Foo1()& public async Foo2(string s1)& public async Foo3(string s2)& private async Foo4(string s3) { ….. return myString; } Trivial Chord = Regular method
public class Buffer { public string Get() & public async Put(string s) { return s; } } Chord Put(“1”) Get() Put(“3”) Thread 1 b.Put(“1”); Writeln(b.Get()); Writeln(b.Get()); b.Put(“4”); Thread 2 Writeln(b.Get()); b.Put(“2”); b.Put(“3”); Writeln(b.Get()); OUTPUT: 1 2 3 4
Buffer buff = new Buffer(); buff.Put(“blue”); buff.Put(“sky”); Console.Write(buff.Get()); Console.Write(buff.Get()); bluesky skyblue [In a real implementation the nondeterminism may be resolved]
Thread safety • The chord mechanism is thread safe • The locking that is required is generated automatically by the compiler • deciding whether any chord is enabled by a call and, if so, removing the other pending calls from the queues and scheduling the body for execution, is an atomic operation. • no monitor-like mutual exclusion between chord bodies • Any mutual exclusion that is required must be explicitly programmed in terms of synchronization conditions in chord headers
A Simple Cell Class public class OneCell { public OneCell() { empty(); } public void Put(object o)& private async empty() { contains(o); } public object Get()& private async contains(object o) { empty(); return o; } }
One method in multiple chords It is possible (and common) to have multiple chords involving a given method public class Buffer { public string Get() & public async Put(string s) { return s; } public string Get() & public async Put(int n) { return n.ToString(); } } nondeterminism
Within a single method-header public void Random(out int a) { a = …. } Int a ; Random(out a); public void AddOne(ref int a) { a++; } Int x = 7; AddOne(ref x); • If return-type is async then the formal parameter list formals may not contain any ref or out parameter modifier
Within a single chord-declaration • At most one method-header may have a non-async return-type • If the chord has a method-header with return-type type, then body may use return statements with type expressions, otherwise body may use empty return statements • All the formals appearing in method-headers must have distinct identifiers
Within a single chord-declaration – cont’ • Two method-headers may not have both the same member-name and the same argument type signature • The method-headers must either all declare instance methods or all declare static methods
Within a particular class • All method-headers with the same member-name and argument type signature must have the same return-type and identical sets of modifiers public string Get() & public async Put(string s) { return s; } private int Get() & public async Put(int n) { return n.ToString(); }
struct/class class CL { public int x ; } public void foo() { CL c1,c2 ; c1 = new CL() ; c1.x = 7 ; c2 = c1 ; c1.x = 18 ; …. } struct ST { public int x ; } public void foo() { ST s1,s2 ; s1.x = 7 ; s2 = s1 ; s1.x = 18 ; …. }
Within a particular class – cont’ • If it is a value class (struct), then only static methods may appear in non-trivial chords
virtual-override Class A { public void foo1() { …. } public virtual void foo2() { …. } } Class B : A { public override void foo2() { …. } }
class C { public virtual void f () & public virtual async g() { /∗ body1 ∗/ } public virtual void f () & public virtual async h() { /∗ body2 ∗/ } } class D : C { public override async g() { /∗ body3 ∗/ } } class E { public virtual void f() & private async g() { /∗ body4 ∗/ } }
Within a particular class – cont’ If any chord-declaration includes a virtual method m with the override modifier, then any method n that appears in a chord with m in the super class containing the overridden definition of m must also be overridden in the subclass
RendezVous class RendezVous { privateclass Thunk { int wait() & async reply(int j ) {return j ;} } public int f (int i) { Thunk t = new Thunk(); af (i, t); return t.wait(); } private async af (int i, Thunk t) & public int g(int j ) { t . reply( j ); // returning to f return i; // returning to g } }
ReaderWriter 1 class ReaderWriter { ReaderWriter() {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 void Exclusive()& async idle() {} public void ReleaseExclusive() { idle(); } }
ReaderWriter 2 class ReaderWriter { ReaderWriter() { idle(); } private int n = 0; // protected by s() 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(); } }
class ReaderWriterFair { ReaderWriter() { idle(); } private int n = 0; // protected by s() 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() {} }
Delegate delegate bool MyDlg(string s,int I); MyDlg d = new MyDlg(MyObj.f); d(“Hello”, 7);
async & void • async is a subtype of void • A void delegate may be created from an async method • An async method may override a void one • An async method may implement a void method in an interface
Combining Asynchronous Messages public delegate async IntCallback(int result); public class Service { public async Request(string arg, IntCallback cb) { int r ; . . . // do some work cb(r); // send the result back } }
class Client { public static void Main(string[] args) { Service s1 = . . . ; Service s2 = . . . ; Join2 x = new Join2(); s1.Request(args[0], x . firstcb); s2.Request(args[1], x . secondcb); . . . // do something useful in the meantime. . . int i, j ; x.wait(out i, out j ); // wait for both results to come back . . . // do something with them } }
class Join2 { public IntCallback firstcb; public IntCallback secondcb; public Join2() { firstcb = new IntCallback(first); secondcb = new IntCallback(second); } public void wait(out int i, out int j ) & async first(int fst) & async second(int snd) { i = fst; j = snd; } }
Active Objects public abstract class ActiveObject { protected bool done; abstract protected void ProcessMessage(); public ActiveObject () { done = false; mainLoop(); } async mainLoop() { while (!done) ProcessMessage(); } }
public class StockServer : ActiveObject { public async AddClient(Client c) // add new client & override protected void ProcessMessage() { // Body } public async CloseDown() // request to terminate & override protected void ProcessMessage() { done = true; } }
Remarks on Concrete Syntax class ReaderWriter { privateasync idle(); // Just signatures. Any modifiers or private async s(int); // attributes would occur here too public ReaderWriter() { idle(); } public void Shared() when idle() { s(1); } when s(int n) { s(n + 1); } public void ReleaseShared() when s(int n) { if (n == 1) idle(); else s(n − 1); } public void Exclusive() when idle() {} ….
References • Modern Concurrency Abstractions for C#.NICK BENTON, LUCA CARDELLI, and CEDRIC FOURNET. Microsoft Research. • Applied Microsoft .NET Framework Programming.Jeffrey Richter. Microsoft Press. • Java: How to Program, 4th ed. H.M. Deitel, P.J. Deitel. Prentice Hall, 2002. • Monitors: An operating system structuring concept.HOARE, C. A. R. 1974. Comm. ACM 17, 10 (Oct.), 549–557. • Thread Synchronization Fairness in the .NET CLR. Jeffrey Richter. 2003.