Outline 0024 Spring 2010 13 :: 2 CSP: communicating sequential - - PowerPoint PPT Presentation

outline
SMART_READER_LITE
LIVE PREVIEW

Outline 0024 Spring 2010 13 :: 2 CSP: communicating sequential - - PowerPoint PPT Presentation

Outline 0024 Spring 2010 13 :: 2 CSP: communicating sequential processes Synchronous communication with global channels Channels are the only state that is shared between threads No shared objects, shared


slide-1
SLIDE 1
slide-2
SLIDE 2

– 13 :: 2 – 0024 Spring 2010

Outline

slide-3
SLIDE 3

– 13 :: 3 – 0024 Spring 2010

CSP: communicating sequential processes

Synchronous communication with global channels

Channels are the only state that is shared between threads

No shared objects, shared references, or shared arrays

Only data can be transmitted -- no point to send a reference

Restrictive?

Yes and no.

Too restrictive to write interesting programs?

slide-4
SLIDE 4

– 13 :: 4 – 0024 Spring 2010

More details

Unit of transfer (“message”)

Basic model: integers (int) Could be any object

What should the consumer do if there is no message?

Wait.

What should the producer do if the consumer is not ready to receive a message?

Wait.

Should messages be buffered?

No. But well see in a few minutes how to create buffers

slide-5
SLIDE 5

– 13 :: 5 – 0024 Spring 2010

Operations

Many options for syntax. Send: output data into channel ch

ch ! data ch <- data ch.write(data) put(ch, data)

Receive: get data from channel (“input”)

ch ? data ch -> data data = ch.read() get(ch, data)

slide-6
SLIDE 6

– 13 :: 6 – 0024 Spring 2010

Operations, continued

Think of “data” as an int or another useful object

The type/class must be known

Extensions (in the literature): get(ch, data1, data2, .., dataN) Sometimes you want to use a “signal”

Could be incoded in an integer

Example: consumer can ask for more data (signal_1) or stop the

stream (signal_2)

Better to be explicit: give it a name Need mechanism to send and receive a signal

slide-7
SLIDE 7

– 13 :: 7 – 0024 Spring 2010

Operations, continued

get(ch, signal_X()) // also written as ch?signal_X() From channel ch, input the signal “signal_X”. Refuse to input any other signal

Example (in a producer): get(ch_from_consumer, more())

put(ch, signal_Y()) // also written as ch!signal_Y() Send signal “signal_Y” to ch get(ch[j], x) -- on channel ch[j] read x

slide-8
SLIDE 8

– 13 :: 8 – 0024 Spring 2010

Why bother?

Coupling of data exchange (between threads) and synchronization

Synchronization implied - only when data are ready (to

receive) or can be sent

One mechanism to deal with Input/output are well-understood (and necessary)

By extending get/put to communicate with another thread we

can deal with multiple threads

No need to pick one from a long list of synchronization primitives

Semaphores? Monitors? Event queues? Many others that we have not covered in class

slide-9
SLIDE 9

– 13 :: 9 – 0024 Spring 2010

Why bother in this class?

Proofs are simpler, reasoning is simpler

No need to deal with temporal logic: receiving an item

implies synchronization

Not all systems support shared objects/references

Java works fine for a multi-processor/multi-core system --

but what if you want to run on a workstation cluster ?

.. on a cloud ? .. on a collection of volunteered home computers

CSP is a model for (simple) message passing

CSP really a model - must be embedded in a programming

language

There is a Java package

Ill deviate from the Java syntax for now a little

Model to deal with streams

slide-10
SLIDE 10

– 13 :: 10 – 0024 Spring 2010

Sequencing of communication

Recall: all variable names are local, ch1, ch2 connect A & B

Thread A: . . Get(ch1, x) -- wait for B .

  • - transfer happens, x now 6

. Put(ch2, 2*x) -- wait for B .

  • - transfer happens

Thread B: y = 5; . . Put(ch1, y+1)

  • - transfer happens

. . Get(ch2, y)

  • - transfer happens
slide-11
SLIDE 11

– 13 :: 11 – 0024 Spring 2010

Broadcasting

Problem: take input stream and forward the data items to two “worker” threads

in, out1, out2: channels

Thread B: while ( true ) { get(in, item); put(out1, item); put(out2, item); }

slide-12
SLIDE 12

– 13 :: 12 – 0024 Spring 2010

Experiment

Write a simple CSP program to perform a “join” of two streams: take input from two input channels and forward it to an output channel. Forward as fast as possible, you must maintain relative order (as defined by each channel) but the inputs from both channels can be mixed freely.

slide-13
SLIDE 13

– 13 :: 13 – 0024 Spring 2010

Problems?

What would you like to add to CSP to make it possible to write such a program? What is the source of the problem?

slide-14
SLIDE 14

– 13 :: 14 – 0024 Spring 2010

Guarded commands

A guarded command consists of a guard and a block (of statements)

  • guard -> { block }

If the guard evaluates to true, the statement block is executed. Guards can contain only logical expressions without side effects

Input is allowed

One input operation, must be the last of a logical AND

Output is not allowed

slide-15
SLIDE 15

– 13 :: 15 – 0024 Spring 2010

Guarded commands

Can be grouped in a select clause select {

  • guard1 -> {block1};
  • guard2 -> {block2};

…. } Any guard that evaluates to true may trigger execution

  • f its block.

Only one block (of those with a guard that evaluates to true) is executed.

Select fails if no guard evaluates to true

slide-16
SLIDE 16

– 13 :: 16 – 0024 Spring 2010

Failure and waiting

select {

  • (j < 10) -> {j --;};

(get(ch, x)) -> {j = x;}; } If the thread that provides input to “ch” terminates (or has terminated) the corresponding “get” operation fails. Otherwise get waits for input. Same for put.

slide-17
SLIDE 17

– 13 :: 17 – 0024 Spring 2010

Looping

while select { guarded command 1; guarded command 2; guarded command n; } Loop until all guarded commands fail.

slide-18
SLIDE 18

– 13 :: 18 – 0024 Spring 2010

Solution (one)

Write a simple CSP program to perform a “join” of two streams: take input from two input channels and forward it to an output channel. Forward as fast as possible, you must maintain relative order (as defined by each channel) but the inputs from both channels can be mixed freely. while select { get(in1, x) -> put(out, x); get(in2, x) -> put(out, x); }; Terminates if both sources for in1 and in2 have terminated.

slide-19
SLIDE 19

– 13 :: 19 – 0024 Spring 2010

Non-determinism

slide-20
SLIDE 20

– 13 :: 20 – 0024 Spring 2010

Comments

slide-21
SLIDE 21

– 13 :: 21 – 0024 Spring 2010

Division with remainder

Construct a program that accepts a positive dividend and divisor and returns their integer quotient and remainder.

slide-22
SLIDE 22

– 13 :: 22 – 0024 Spring 2010

int x, y; while select { get(in, x, y) -> { int q, r; q = 0; r = x;

  • while select {
  • (r y) -> { r = r - y; q++; };
  • };
  • put(out, q, r);

}; };

slide-23
SLIDE 23

– 13 :: 23 – 0024 Spring 2010

Buffering

CSP provides synchronous communication. If you need buffering you must introduce a separate buffer thread.

Buffer is bounded

Problem: write the program for a buffer thread.

Assume we want to buffer up to 10 integers Buffer takes input as it is generated by “producer” Passes on buffered data as requested by “consumer”

Consumer send signal “more” if it is ready for input

slide-24
SLIDE 24

– 13 :: 24 – 0024 Spring 2010

We need a buffer array, counters for input and output, plus three channels to connect to.

source: producer; sink: consumer; request: consumer

signals its ready for data int [ ] buffer = new int[10]; int count_in = 0; int count_out = 0; while select { ((count_in < count_out+10) (get(source,buffer[count_in mod 10]))) -> { count_in++;}; ((count_out < count_in) (get(request,more())) -> {

  • put(sink, buffer[count_out mod 10]; count_out++; } ;

};

slide-25
SLIDE 25

– 13 :: 25 – 0024 Spring 2010

Why (hidden) buffering is bad

Programs can fail in unexpected ways if they assume an infinite buffer

No buffer is infinite Different systems may approximate the infinite buffer

differently

Problem: a producer sends a set (sequence) of data to a consumer. Then – using a different channel – it sends the size of the set. The consumer reads the size of the set to determine how many items to retrieve.

slide-26
SLIDE 26

– 13 :: 26 – 0024 Spring 2010

Implementation strategy

slide-27
SLIDE 27

– 13 :: 27 – 0024 Spring 2010

Simple solution

Thread Producer: int [ ] b; int j = 0; while (cond) { put(ch1, b[j++]); } put(ch2, j); Thread Consumer: int j=0; int count; int [ ] b; get(ch2, count); while (j<count){ get(ch1,b[j++]); }

slide-28
SLIDE 28

– 13 :: 28 – 0024 Spring 2010

Real solution

slide-29
SLIDE 29

– 13 :: 29 – 0024 Spring 2010

Snapshot

P

  • C
  • Read so far
  • Filled up to

here

slide-30
SLIDE 30

– 13 :: 30 – 0024 Spring 2010

Real solution 2

slide-31
SLIDE 31

– 13 :: 31 – 0024 Spring 2010

Snapshot

P

  • C
  • Thread Producer:

int [ ] b; int j = 0; while (cond) { put(ch1, b[j++]); } put(ch2, j); Thread Consumer: int j=0; int count; int [ ] b; get(ch2, count); while (j<count){ get(ch1,b[j++]); }

slide-32
SLIDE 32

– 13 :: 32 – 0024 Spring 2010

Bad situation

slide-33
SLIDE 33

– 13 :: 33 – 0024 Spring 2010

Snapshot

P

  • C
  • Thread Producer:

int [ ] b; int j = 0; while (cond) { put(ch1, b[j++]); } put(ch2, j); Thread Consumer: int j=0; int count; int [ ] b; get(ch2, count); while (j<count){ get(ch1,b[j++]); }

slide-34
SLIDE 34

– 13 :: 34 – 0024 Spring 2010

Synchronous send/receive

slide-35
SLIDE 35

– 13 :: 35 – 0024 Spring 2010

Note

Thread Producer: int [ ] b; int j = 0; while (cond) { put(ch1, b[j++]); } put(ch2, j); Thread Consumer: int j=0; int count; int [ ] b; get(ch2, count); while (j<count){ get(ch1,b[j++]); }

slide-36
SLIDE 36

– 13 :: 36 – 0024 Spring 2010

Channels

To simplify many programming problems, we allow multiple “writers” for a channel.

May even substitute the name of a channel by the name of a

thread.

slide-37
SLIDE 37

– 13 :: 37 – 0024 Spring 2010

Semaphores

Implement an integer semaphore shared by an array of threads (with X[0 … 99] the channels to the threads) Call your signals p() and v(). Then (if we call the semaphore thread S), all other threads can use put(S, p()) and put(S, v()) to increment/decrement the semaphore.

slide-38
SLIDE 38

– 13 :: 38 – 0024 Spring 2010

Semaphores

Implement an integer semaphore shared by an array of threads (with X[0 … 99] the channels to the threads). Decrementing the semaphore must be delayed if the value is not positive. int val = 0; while select { get(X[j], v()) -> { val++; } ; ((val > 0) (get(X[j], p())) -> { val--;}; }; Need to limit the range of values for j

slide-39
SLIDE 39

– 13 :: 39 – 0024 Spring 2010

Semaphores

(j:low_range .. high_range): shorthand for replication int val = 0; while select { (j:0..99): get(X[j], v()) -> { val++; } ; (j:0..99): ((val > 0) (get(X[j], p())) -> { val--;}; };

slide-40
SLIDE 40

– 13 :: 40 – 0024 Spring 2010

Dining philosophers

Can you come up with a CSP solution to this problem?

slide-41
SLIDE 41

– 13 :: 41 – 0024 Spring 2010

Other examples

slide-42
SLIDE 42

– 13 :: 42 – 0024 Spring 2010

Added bonus

Message passing programs sometimes adapt well to hierarchical memory systems

A message is received … as a result it is in memory (close to

the core that wants to receive it)

Any transfer cost (from a different core/memory region) has

been paid for

The message is processed … it helps that it is in memory

nearby.

After a message is produced, the memory cannot be

recycled before it is sure that the message has reached its destination.

Of course, in real system your mileage may vary.

Not all problems map well into message passing Not all systems support efficient message passing