The top software developers are more productive than
average software developers not by a factor of 10X or
100X or even 1000X but by 10,000X.
Nathan Myhrvold
Review and Overview
| wait: | down ( mutex ); |
| access_CS(); | |
| signal: | up ( mutex ); |
Example
Let us look at an example of semaphores. In figure A, there are three semaphores: S1 has a value of zero and process P1 is blocked on S1; S2 has a value of three, meaning three more processes may execute a down operation on S2 without being put to sleep; S3 has a value of zero, and has two sleeping processes, P4 and P5, blocked on it.

Now let us look at what happens when a process executes an UP on S1. In figure B, process P1 is activated by an UP operation. It executes a DOWN on S1 and enters its critical section. The state of the semaphores after these actions has now changed.

Example:
Reader-Writers Problem with Reader's priority.
//C/C++ psuedo code for reader-writer problem with reader's priority
//global variables
int nreaders; //number of readers reading
semaphore mutex, wmutex, srmutex;
void reader()
{
mutex.wait(); //P ( mutex ), if some readers arrive while writer writing
//the first reader will be blocked on 'wmutex' and subsequent
//readers blocked on mutex
if ( nreaders == 0 ) {
++nreaders;
wmutex.wait(); //P ( wmutex ), blocks a writer or a reader
} else
++nreaders;
mutex.signal(); //V ( mutex )
read_file();
mutex.wait(); //P ( mutex )
--nreaders;
if ( nreaders == 0 )
wmutex.signal(); //V ( wmutex )
mutex.signal(); //V ( mutex )
}
void writer()
{
srmutex.wait(); //P ( srmutex )
wmutex.wait(); //P ( wmutext )
write_file();
wmutex.signal(); //V ( wmutex )
srmutex.signal(); //V ( srmutex )
}
int main()
{
//initialization
mutex = wmutex = srmutex = semaphore ( 1 );
nreaders = 0;
....
return 1;
}
|
Weakness
Weakness:
Procedures |
Hollow Region( multiple processes can be active here ) |
| |
Hollow Region( multiple processes can be active here ) |
| |
path S end
S : execution history
; sequencing -- statement executions are in sequence
+ selection -- only one statement can be executed at a time
{} concurrency -- concurrent execution
e.g. path write + { read } end
either write or several read
e.g. path { write ; read } end
at any time, there can be any number of instantiations of
path write; read.
Example: readers-writers problem with weak reader's priority ( several readers can read file at the same time but only one writer can write to the file at a time; an arriving reader has higher priority than a waiting writer if reading has occurred, but when reading or writing is done, reader and writer have same priority, i.e. chosen randomly )
Output command = <destination process id> ! <expression>
e.g. mouse?xy, screen!xy
( read input from mouse, save value in xy; the value of xy
is output to the screen )
Concurrent processes :
[process P1's code||process P2's code||
..... ||process Pn's code]
basically :
if ( G )
CL
evaluate G, if false, ( i.e. guard fails ), CL won't be evaluated
Alternative command
G2 -->CL2
.....
Gn -->CLn
Repetitive command
G2 -->CL2
.....
Gn -->CLn ]
CSP parallelism, on its own, does not introduce non-determinism.
Example
start with i = 0, then repetitively scan until either i ≥ size or some content( i ) equals n
Example
Repeatedly receives a character from the process P1, and then sends that character to process P2.
the command terminates when P1 terminates
Example:Producer-Consumer Problem in CSP
process bounded-buffer
buffer:(0..9) item;
in,out:integer; in := 0; out := 0;
comment 0 <= out <= in <= out+10;
*[in < out + 10; producer?buffer(in mod 10) ->
in := in + 1;
out < in; consumer?more( ) ->
consumer!buffer(out mod 10); out := out + 1;]
Advantages of CSP
Weakness of CSP
The rendezvous effectively combines mutual exclusion, task, synchronization, and interprocess communication
Two tasks may rendezvous at once in Ada -- a caller and a server
server accepts calls from any caller but only one caller
may rendezvous with the server, others wait
First-come-first-served
Ada Task:
task ResourceController is --task specification entry GetControl; entry RelinquishControl; end ResourceController task body ResourceController is --body begin loop accept GetControl; accept RelinquishControl; end loop; end ResourceController; . . . |
Example: producer-consumer with single buffer
task SingleBuffer is entry Store ( x:buffer ); entry Remove ( y:buffer ); end; task body SingleBuffer is temp:buffer; --shared variable begin loop accept Store ( x:buffer ); --Store and remove temp = x; --are executed alternately end Store; accept Remove ( y:buffer ); y = temp; end Remove; end loop end SingleBuffer; |
select -- make tasks to accept calls in a more flexible way
select when Condition 1 => accept Entry 1 statements; or when Condition 2 => accept Entry 2 statements; or . . . else statements; end select |
Example: producer-consumer with bounded buffer
task bounded-buffer is entry store( x:buffer ); entry remove( y:buffer ); end; task body bounded-buffer is ring:[0..9] of buffer; head, tail: integer; head = 0; tail = 0; begin loop select when tail < head + 10 = > --queue not full yet accept store( x:buffer ); ring[tail mod 10] = x; --put item in buffer tail = tail + 1; --next slot end store; or when head < tail = > --queue not empty accept remove( y:buffer ); y = ring[head mod 10]; --get item from ring head = head + 1; --next slot end remove; end select; end loop end bounded-buffer; |
![]() |
Simulating path expressions in Ada
entries A, B B must follow A: accept A; accept B; specifying either A or B ( not both ) can be executed: select when ( x > 0 ) = > accept A; or when ( x <= 0 ) = > accept B; end select; specifying any number ( including 0 ) of calls to A: loop select when ( x > 0 ) = > accept A; else exit; end select; end loop |