libcppa An actor library for C++ with extensible group semantic - - PowerPoint PPT Presentation

libcppa
SMART_READER_LITE
LIVE PREVIEW

libcppa An actor library for C++ with extensible group semantic - - PowerPoint PPT Presentation

libcppa An actor library for C++ with extensible group semantic libcppa Dominik Charousset July 2011 Dominik Charousset (HAW Hamburg) libcppa July 2011 1 / 24 Agenda Motivation 1 Concurrency Approaches 2 The Actor Model 3 libcppa 4


slide-1
SLIDE 1

libcppa

An actor library for C++ with extensible group semantic

libcppa

Dominik Charousset July 2011

Dominik Charousset (HAW Hamburg) libcppa July 2011 1 / 24

slide-2
SLIDE 2

Agenda

1

Motivation

2

Concurrency Approaches

3

The Actor Model

4

libcppa

5

libcppa Architecture

6

Questions & Answers

Dominik Charousset (HAW Hamburg) libcppa July 2011 2 / 24

slide-3
SLIDE 3

Motivation

Herb Sutter: “The Free Lunch Is Over”

http://www.gotw.ca/publications/concurrency-ddj.htm

CPU clock speed stagnates More cores instead of more clock speed

Dominik Charousset (HAW Hamburg) libcppa July 2011 3 / 24

slide-4
SLIDE 4

Motivation

Herb Sutter: “The Free Lunch Is Over”

http://www.gotw.ca/publications/concurrency-ddj.htm

CPU clock speed stagnates More cores instead of more clock speed ⇒ Single-threaded Software doesn’t benefit from new hardware

Dominik Charousset (HAW Hamburg) libcppa July 2011 3 / 24

slide-5
SLIDE 5

Motivation

Herb Sutter: “The Free Lunch Is Over” – Consequence

“Software has to double the amount of parallelism that it can support every two years.” – Shekhar Y. Borkar (Intel)

Dominik Charousset (HAW Hamburg) libcppa July 2011 4 / 24

slide-6
SLIDE 6

Motivation

Multithreading In C-like Languages

A multithreaded environment requires, that each object (in the shared memory) has to be thread safe Immutable objects are always thread-safe (if initialization is done) Stateful objects need synchronization

Dominik Charousset (HAW Hamburg) libcppa July 2011 5 / 24

slide-7
SLIDE 7

Motivation

Multithreading In C-like Languages

A multithreaded environment requires, that each object (in the shared memory) has to be thread safe Immutable objects are always thread-safe (if initialization is done) Stateful objects need synchronization ⇒ The developer is responsible for thread safety! Errors lead to ...

Race conditions Deadlocks/Lifelocks Poor scalability due to queueing (Coarse-Grained Locking)

Dominik Charousset (HAW Hamburg) libcppa July 2011 5 / 24

slide-8
SLIDE 8

Motivation

Multithreading In C-like Languages

A multithreaded environment requires, that each object (in the shared memory) has to be thread safe Immutable objects are always thread-safe (if initialization is done) Stateful objects need synchronization ⇒ The developer is responsible for thread safety! Errors lead to ...

Race conditions Deadlocks/Lifelocks Poor scalability due to queueing (Coarse-Grained Locking)

“Mutable stateful objects are the new spaghetti code” – Rich Hickey

Dominik Charousset (HAW Hamburg) libcppa July 2011 5 / 24

slide-9
SLIDE 9

Motivation

Multithreading in C-like languages – Example 1

class Subject { private int value; private List<Listener> listeners = ...; public interface Listener { public void stateChanged(int newValue); } public synchronized void addListener(Listener listener) { listeners.add(listener); } public synchronized void setValue(int newValue) { value = newValue; for (Listener l : listeners) { l.stateChanged(newValue); } } }

Dominik Charousset (HAW Hamburg) libcppa July 2011 6 / 24

slide-10
SLIDE 10

Motivation

Multithreading in C-like languages – Example 1

class FooBar { private Subject s; public synchronized void foo() { ... s.addListener(...); ... } public synchronized void bar() { ... } }

Dominik Charousset (HAW Hamburg) libcppa July 2011 7 / 24

slide-11
SLIDE 11

Motivation

Multithreading in C-like languages – Example 1

Thread1 Thread2

Subject s FooBar fb

Dominik Charousset (HAW Hamburg) libcppa July 2011 8 / 24

slide-12
SLIDE 12

Motivation

Multithreading in C-like languages – Example 1

Thread1 Thread2

Subject s FooBar fb Listener li

addListener(li)

public void stateChanged(int val) { .... fb.bar(); .... }

Dominik Charousset (HAW Hamburg) libcppa July 2011 8 / 24

slide-13
SLIDE 13

Motivation

Multithreading in C-like languages – Example 1

Thread1 Thread2

FooBar fb Listener li

setValue(...)

Subject s

Dominik Charousset (HAW Hamburg) libcppa July 2011 8 / 24

slide-14
SLIDE 14

Motivation

Multithreading in C-like languages – Example 1

Thread1 Thread2

Listener li

setValue(...) foo() stateChanged(...)

Subject s FooBar fb

Dominik Charousset (HAW Hamburg) libcppa July 2011 8 / 24

slide-15
SLIDE 15

Motivation

Multithreading in C-like languages – Example 1

Thread1 Thread2

Listener li

setValue(...) foo() stateChanged(...) bar() addListener(...)

Subject s FooBar fb

Dominik Charousset (HAW Hamburg) libcppa July 2011 8 / 24

slide-16
SLIDE 16

Motivation

Multithreading in C-like languages – Example 1

Programming with locks increases complexity and error-proneness. Libraries (objects) with locks are no longer black boxes The user have to know about implementation details (“which method uses which lock?”)

Dominik Charousset (HAW Hamburg) libcppa July 2011 9 / 24

slide-17
SLIDE 17

Motivation

Multithreading in C-like languages – Example 2 c l a s s Foo { // immutable s t a t i c Foo∗ ptr ; s t a t i c Foo∗ i n s t a n c e () { // 1 s t t e s t i f ( ptr == n u l l p t r ) { Lock l ock ; // 2nd t e s t i f ( ptr == n u l l p t r ) ptr = new Foo ; } return ptr ; } // . . . }

Adapted from: “C++ and the Perils of Double-Checked Locking” (Meyers & Alexandrescu, 2004) Dominik Charousset (HAW Hamburg) libcppa July 2011 10 / 24

slide-18
SLIDE 18

Motivation

Multithreading in C-like languages – Example 2 c l a s s Foo { // immutable s t a t i c Foo∗ ptr ; s t a t i c Foo∗ i n s t a n c e () { // 1 s t t e s t i f ( ptr == n u l l p t r ) { Lock l ock ; // 2nd t e s t i f ( ptr == n u l l p t r ) ptr = new Foo ; } return ptr ; } // . . . }

Problem: “ptr = new Foo” is not atomic:

  • 1. Allocate memory
  • 2. Call constructor of Foo
  • 3. Assign memory address to ptr

Adapted from: “C++ and the Perils of Double-Checked Locking” (Meyers & Alexandrescu, 2004) Dominik Charousset (HAW Hamburg) libcppa July 2011 10 / 24

slide-19
SLIDE 19

Motivation

Multithreading in C-like languages – Example 2 c l a s s Foo { // immutable s t a t i c Foo∗ ptr ; s t a t i c Foo∗ i n s t a n c e () { // 1 s t t e s t i f ( ptr == n u l l p t r ) { Lock l ock ; // 2nd t e s t i f ( ptr == n u l l p t r ) ptr = new Foo ; } return ptr ; } // . . . }

Problem: “ptr = new Foo” is not atomic:

  • 1. Allocate memory
  • 2. Call constructor of Foo
  • 3. Assign memory address to ptr

If 3 happens before 2, a second thread might deallocate ptr before the constructor was called (undefined behavior).

Adapted from: “C++ and the Perils of Double-Checked Locking” (Meyers & Alexandrescu, 2004) Dominik Charousset (HAW Hamburg) libcppa July 2011 10 / 24

slide-20
SLIDE 20

Motivation

Multithreading in C-like languages – Example 2

Concurrency with low-level primitives requires a lot of expert knowledge. Seemingly correct code can lead to undefined behavior Almost impossible to verify by testing An implementation can be thread-safe on a uniprocessor machine (“timeslice-based parallelism”) but can lead to race conditions on a multiprocessor machine (true hardware concurrency)

Dominik Charousset (HAW Hamburg) libcppa July 2011 11 / 24

slide-21
SLIDE 21

Concurrency Approaches

Transactional Memory

Race condition free shared memory Reads & writes are atomic and transactional “all or nothing” writes Readers don’t interfere writers and vice versa In hardware or software (e.g. Clojure)

Dominik Charousset (HAW Hamburg) libcppa July 2011 12 / 24

slide-22
SLIDE 22

Concurrency Approaches

Join-Calculus (JoCaml)

  • 1. def fruit(f) & cake(c) = print_endline (fˆ“ ”ˆ c) ; 0

val fruit : string Join.chan = <abstr> val cake : string Join.chan = <abstr>

  • 2. spawn fruit “apple” & cake “pie”
  • 3. spawn fruit “apple” & fruit “lime” & cake “pie” & cake “torte”

Join-calculus is a member of the π calculus family Processes communicate (synchronize) via ports

Dominik Charousset (HAW Hamburg) libcppa July 2011 13 / 24

slide-23
SLIDE 23

Concurrency Approaches

Join-Calculus (JoCaml)

  • 1. def fruit(f) & cake(c) = print_endline (fˆ“ ”ˆ c) ; 0

val fruit : string Join.chan = <abstr> val cake : string Join.chan = <abstr>

  • 2. spawn fruit “apple” & cake “pie”
  • 3. spawn fruit “apple” & fruit “lime” & cake “pie” & cake “torte”

Join-calculus is a member of the π calculus family Processes communicate (synchronize) via ports Source code example:

  • 1. Define two ports and the guarded process print_endline ...
  • 2. Prints “apple pie”
  • 3. Prints “apple pie”, “lime torte” or “apple torte”, “lime pie”

Dominik Charousset (HAW Hamburg) libcppa July 2011 13 / 24

slide-24
SLIDE 24

Concurrency Approaches

Summary

There are basically two approaches: Provide a safe (free of race conditions) shared memory Model concurrent tasks/processes as independent components, communicating via messages/channels/ports

Dominik Charousset (HAW Hamburg) libcppa July 2011 14 / 24

slide-25
SLIDE 25

Concurrency Approaches

Summary

There are basically two approaches: Provide a safe (free of race conditions) shared memory

Clojure Intel C++ STM Compiler ...

Model concurrent tasks/processes as independent components, communicating via messages/channels/ports

Dominik Charousset (HAW Hamburg) libcppa July 2011 14 / 24

slide-26
SLIDE 26

Concurrency Approaches

Summary

There are basically two approaches: Provide a safe (free of race conditions) shared memory

Clojure Intel C++ STM Compiler ...

Model concurrent tasks/processes as independent components, communicating via messages/channels/ports

Erlang (resp. the Actor Model in general) Google Go (channel based communication) ...

Dominik Charousset (HAW Hamburg) libcppa July 2011 14 / 24

slide-27
SLIDE 27

Concurrency Approaches

Summary

We have to enable “average programmers” to write both (multiprocessor) safe and scalable applications. No shared memory or transactional memory Explicit communication of independent software components (channels, ports, ...) instead of implicit communication via shared memory segments and locks High-level concepts with reasonable metaphors

Dominik Charousset (HAW Hamburg) libcppa July 2011 15 / 24

slide-28
SLIDE 28

The Actor Model

Definition

Actors are self-contained, concurrent computation entities, that ... Communicate only via (asynchronous) message passing Don’t share memory Can create (“spawn”) new Actors

Dominik Charousset (HAW Hamburg) libcppa July 2011 16 / 24

slide-29
SLIDE 29

The Actor Model

Benefits

Race conditions are avoided by design (no shared memory comm.)

Dominik Charousset (HAW Hamburg) libcppa July 2011 17 / 24

slide-30
SLIDE 30

The Actor Model

Benefits

Race conditions are avoided by design (no shared memory comm.) High-level, explicit communication

Dominik Charousset (HAW Hamburg) libcppa July 2011 17 / 24

slide-31
SLIDE 31

The Actor Model

Benefits

Race conditions are avoided by design (no shared memory comm.) High-level, explicit communication Applies to both concurrency and distribution (network transparency thanks to message passing)

Dominik Charousset (HAW Hamburg) libcppa July 2011 17 / 24

slide-32
SLIDE 32

The Actor Model

Benefits

Race conditions are avoided by design (no shared memory comm.) High-level, explicit communication Applies to both concurrency and distribution (network transparency thanks to message passing) Inspired several implementations either as basis for languages (Erlang) or as library/framework (Scala, Kilim, Retlang, ...)

Dominik Charousset (HAW Hamburg) libcppa July 2011 17 / 24

slide-33
SLIDE 33

libcppa

Why C++?

Thousands of active developers and huge, existing code bases Still no high-level concurrency abstraction in C++11 New language features (lambda expression, variadic templates, ...) ease development of libraries as internal DSL

Dominik Charousset (HAW Hamburg) libcppa July 2011 18 / 24

slide-34
SLIDE 34

libcppa

Goals

An actor library for C++ as internal DSL

Dominik Charousset (HAW Hamburg) libcppa July 2011 19 / 24

slide-35
SLIDE 35

libcppa

Goals

An actor library for C++ as internal DSL Network transparency (ease distribution)

Dominik Charousset (HAW Hamburg) libcppa July 2011 19 / 24

slide-36
SLIDE 36

libcppa

Goals

An actor library for C++ as internal DSL Network transparency (ease distribution) Pattern matching for messages

Dominik Charousset (HAW Hamburg) libcppa July 2011 19 / 24

slide-37
SLIDE 37

libcppa

Goals

An actor library for C++ as internal DSL Network transparency (ease distribution) Pattern matching for messages Extensible group (N:M) communication API

In-process (event handling) Inter-process (services, system-wide events) Network layer multicast (IP, Overlay, H∀Mcast, ...)

Dominik Charousset (HAW Hamburg) libcppa July 2011 19 / 24

slide-38
SLIDE 38

libcppa

Goals

An actor library for C++ as internal DSL Network transparency (ease distribution) Pattern matching for messages Extensible group (N:M) communication API

In-process (event handling) Inter-process (services, system-wide events) Network layer multicast (IP, Overlay, H∀Mcast, ...)

Lightweight, scheduled Actors

Dominik Charousset (HAW Hamburg) libcppa July 2011 19 / 24

slide-39
SLIDE 39

libcppa

Actor Scheduling

Actors are lighweight tasks, scheduled in a thread pool

uninitialized ready blocked running detached exited

Small overhead for spawn/delete operations

Dominik Charousset (HAW Hamburg) libcppa July 2011 20 / 24

slide-40
SLIDE 40

libcppa

Group Communication

Actors can join and leave groups A group is identified by module name + group identifier Users can add new modules (e.g. for “ip”, “H∀Mcast”, ...)

Dominik Charousset (HAW Hamburg) libcppa July 2011 21 / 24

slide-41
SLIDE 41

libcppa

Group Communication c l a s s group : // . . . { // . . . v i r t u a l member f u n c t i o n s . . . s t a t i c group ∗ get ( const std : : s t r i n g& module_name , const std : : s t r i n g& g r o u p _ i d e n t i f i e r ) ; s t a t i c void add_module ( module ∗ ) ; };

Actors can join and leave groups A group is identified by module name + group identifier Users can add new modules (e.g. for “ip”, “H∀Mcast”, ...)

Dominik Charousset (HAW Hamburg) libcppa July 2011 21 / 24

slide-42
SLIDE 42

libcppa

Network Transparency

Network

Node A Node B

Actor 1 Actor 2 MM2

Send a message to a remote (“published”) actor

Dominik Charousset (HAW Hamburg) libcppa July 2011 22 / 24

slide-43
SLIDE 43

libcppa

Network Transparency

Network

Node A Node B

Actor 1 Actor 2 MM2 System

remoteActor(host,port)

Send a message to a remote (“published”) actor

Dominik Charousset (HAW Hamburg) libcppa July 2011 22 / 24

slide-44
SLIDE 44

libcppa

Network Transparency

Network

Node A Node B

Actor 1 Actor 2 MM2 MM1 Actor 2 Proxy

Send a message to a remote (“published”) actor

Dominik Charousset (HAW Hamburg) libcppa July 2011 22 / 24

slide-45
SLIDE 45

libcppa

Network Transparency

Network

Node A Node B

Actor 1 Actor 2 MM2 MM1 Actor 2 Proxy

serialize deserialize

Send a message to a remote (“published”) actor

Dominik Charousset (HAW Hamburg) libcppa July 2011 22 / 24

slide-46
SLIDE 46

libcppa

Network Transparency

Network

Node A Node B

Actor 1 Actor 2 MM2 MM1 Actor 2 Proxy

serialize deserialize

Actor 1 Proxy

Send a message to a remote (“published”) actor

Dominik Charousset (HAW Hamburg) libcppa July 2011 22 / 24

slide-47
SLIDE 47

libcppa

Network Transparency

Network

Node A Node B

Actor 1 Actor 2 MM2 MM1 Actor 2 Proxy

serialize deserialize

Actor 1 Proxy

Send a message to a remote (“published”) actor

Dominik Charousset (HAW Hamburg) libcppa July 2011 22 / 24

slide-48
SLIDE 48

libcppa

Example #i n c l u d e "cppa/cppa . hpp" using namespace cppa ; void ping ( ) ; void pong ( actor_ptr ping_actor ) ; i n t main ( int , char ∗∗) { spawn ( pong , spawn ( ping ) ) ; await_all_others_done ( ) ; return 0; }

Dominik Charousset (HAW Hamburg) libcppa July 2011 23 / 24

slide-49
SLIDE 49

libcppa

Example void ping () { receive_loop (

  • n<atom ( "Pong" ) ,

int >() >> [ ] ( i n t value ) { r e p l y ( atom ( " Ping " ) , value + 1 ) ; } ) ; }

Dominik Charousset (HAW Hamburg) libcppa July 2011 24 / 24

slide-50
SLIDE 50

libcppa

Example void pong ( actor_ptr ping_actor ) { l i n k ( ping_actor ) ; // k i c k o f f ping_actor << make_tuple ( atom ( "Pong" ) , 0 ) ; //

  • r :

send ( ping_actor , atom (" Pong ") , 0 ) ; receive_loop (

  • n<atom ( " Ping " ) ,

int >(9) >> [ ] ( ) { // terminate with non−normal e x i t reason q u i t ( exit_reason : : user_defined ) ; } ,

  • n<atom ( " Ping " ) ,

int >() >> [ ] ( i n t value ) { r e p l y ( atom ( "Pong" ) , value + 1 ) ; } ) ; }

Dominik Charousset (HAW Hamburg) libcppa July 2011 25 / 24

slide-51
SLIDE 51

Questions & Answers Thank you for your attention! Questions?

Dominik Charousset (HAW Hamburg) libcppa July 2011 26 / 24