SDSU CS 662: Theory of Parallel Algorithms
SR Parallel

[To Course Home Page]
San Diego State University -- This page last updated February 1, 1996
----------

Contents of SR Parallel Lecture

  1. Concurrent Execution
    1. Concurrent Invocation
    2. Semaphores
    3. Asychronous Message Passing
      1. Semphores and Message Passing
      2. Deadlock?
    4. Real Parallelism
      1. Asynchronous Messages and VM
    5. Remote Procedure Calls
      1. Reply
    6. Rendezvous
    7. Message Passing Reviewed
      1. Synchronization Expressions

Concurrent Execution



resource foo()
	write("Start A")

	process A
		fa k := 1 to 5 -> write("In A");
		af
	end A

	write("Start B")

	process B
		fa k := 1 to 5 -> write("In B");
		af
	end B

	write("All done")
end foo
Output

Start A
Start B
All done
In B
In B
In B
In B
In B
In A
In A
In A
In A
In A


Process Example 2

resource foo()
	var X: int := 0
	write("Before A")

	process A
		write("Start A")
		fa k := 1 to 5 -> X := X - 1  af
		write("End A")
	end A

	write("Between A and B")

	process B
		write("Start B")
		fa k := 1 to 5 -> X := X + 2  af
		write("End B")
	end B

	write("After B")
	final
		write("X is: ", X)
	end
	write("After final")
end foo
Output
Before A
Between A and B
After B
After final
Start A
Start B
End B
End A
X is: 5
Using Common Procedures

resource foo()
	var X: int := 0

	procedure CallMe(What: string[20])
		write(What)
	end

	write("Before A")

	process A
		CallMe("Start A")
		fa k := 1 to 5 -> X := X - 1 af
		CallMe("End A")
	end A

	write("Between A and B")

	process B
		CallMe("Start B")
		fa k := 1 to 5 -> X := X + 2 af
		CallMe("End B")
	end B

end foo

Unabbreviated Form of Process
resource foo()
	op TestProc(How: string[20]) {send}

	write("Before A")

	send TestProc("A")

	write("Between A and B")

	send TestProc("B")

	write("After B")

	proc TestProc(How)
		fa k := 1 to 5 -> write(How) af
	end TestProc

end foo

Output

Before A
Between A and B
After B
B
B
B
B
B
A
A
A
A
A


Procedure vs Process


resource foo()

	op TestProc(How: string[20]) {send, call}

	write("Before A")

	TestProc("A")		#procedure 

	write("Between A and B")

	send TestProc("B") #process

	write("After B")

	proc TestProc(How)
		fa k := 1 to 5 -> write(How) af
	end TestProc
end foo

Output
Before A
A
A
A
A
A
Between A and B
After B
B
B
B
B
B
Just to Show the Processes

resource foo()

	process TestProc(K := 1 to 3, J := 2 to 4)
		var Crap: real

		fa x := 1 to 90,
		   y := 1 to 90 -> Crap := sin(x+y)
		af

		write("K: ", K, "J: ",J)

	end TestProc

end foo
Output

K: 1 J: 2
K: 1 J: 4
K: 2 J: 3
K: 3 J: 2
K: 3 J: 4
K: 2 J: 2
K: 3 J: 3
K: 2 J: 4
K: 1 J: 3


Concurrent Invocation

co command
// command
// command -> block
oc

command is a call invocation, send invocation, or a simple assignment that calls a user-defined function

resource Cotest()
	procedure me(X: string[10])
		write(X)
	end
	co me("A")  // me("B")  oc
		
	write("At the end")
end

Output

A
B
At the end


resource Cotest()
	var X: int := 0
	procedure Y(me: int) returns r: int
		r := me
	end

	co X := Y(4)  //  X := Y(5)  oc
		
	write(X)  #prints 4
end


Concurrent Invocation

resource Cotest()
	procedure me(X: int) returns r: int
	       r := X
	end

	var X: int := 0
	co (K :=  1 to 5) X := me(K) oc
	  
	write(X)		#prints 1
end
	

resource Cotest()
	procedure me(X: int) returns r: int
	       r := X
	end

	var X: int := 0, count: int := 0

	co (K :=  1 to 5) X := me(K) ->
		count++
		write("Count: ", count, "K: ", K)
	oc
	  
	write(X)
end

Output
Count: 1 K: 5
Count: 2 K: 4
Count: 3 K: 3
Count: 4 K: 2
Count: 5 K: 1
1
Concurrent Invocation Example

resource partial_sums()
	var distance: int := 1
	var N: int; getarg(1,N)

	var sum[N], old[N]: int

	procedure save(K: int)
		old[K] := sum[K]
	end

	procedure update(K: int)
		if K > distance -> 
			sum[K] +:= old[K - distance]
		fi
	end

	fa K := 1 to N -> sum[K] := i af

	do distance < N ->
		co (K := 1 to N) save(K) oc
		co (K := 1 to N) update(K) oc
		distance +:= distance #double distance
	od

	fa K := 1 to N -> write(K, sum[K]) af
end

Execution
saturn 36-> sr sums.sr
saturn 37-> a.out 5
1 1
2 3
3 6
4 10
5 15

Semaphores

sem S
V(S) increases S by one
P(S) waits until S is positive, decreases S by 1

resource Sem()
	const N := 4
	var X := 0

	sem SafeX := 1

	process p(K := 1 to N)
		fa L := 1 to 2 ->
			P(SafeX)
			write("Safe Area", K)
			X := X + 1
			V(SafeX)
		af
	end
end
Output

Safe Area 1
Safe Area 1
Safe Area 2
Safe Area 2
Safe Area 3
Safe Area 3
Safe Area 4
Safe Area 4


Arrays of Semaphores
resource Sem()
	const N := 4

	sem Safe[N] := (1, [N-1] 0)

	process p(K := 1 to N)

		fa L := 1 to 2 ->

			P(Safe[K])

			write("Safe Area", K)

			var NextSafe: int := (K mod N) + 1

			V(Safe[NextSafe])
		af
	end
end
Output

Safe Area 1
Safe Area 2
Safe Area 3
Safe Area 4
Safe Area 1
Safe Area 2
Safe Area 3
Safe Area 4


Problems In Semaphore Land
resource SemaLand()
	var X := 0

	sem SafeX := 1

	process A
		do true ->
			P(SafeX)
			X := X + 1
			V(SafeX)
		od
	end

	process B
		do true ->
			P(SafeX)
			X := X - 1
			V(SafeX)
		od
	end

	process C
		do true ->
			P(SafeX)
			write(X)
			V(SafeX)
		od
	end

end

Monitors
global MonitorX
	op increase(amount: int)
	op decrease(amount: int)
	op print()

body MonitorX
	sem SafeX := 1
	var X: int := 0

	proc increase(amount)
		P(SafeX)
		X +:= amount
		V(SafeX)
	end

	proc decrease(amount)
		P(SafeX)
		X -:= amount
		V(SafeX)
	end
end


resource SemFree()
	import MonitorX

	process A
		fa K := 1 to 3 -> increase(2)  af
	end

	process B
		fa K := 1 to 3 -> decrease(1) af
	end

end

Asychronous Message Passing

resource Message()
	op MyMessage(X: int)
	send MyMessage(0)

	process one
		fa K := 1 to 3 -> send MyMessage(K) 
			write("Sent: ",K)
		af
	end

	process two
		var Answer: int

		fa J := 1 to 2 ->receive MyMessage(Answer)
			write("Two received ", Answer)
			nap(0)
		af
	end
		
	process three
		var Answer: int

		fa J := 1 to 2 ->receive MyMessage(Answer)
			write("Three received ", Answer)
		af
	end
end

Two received 0
Sent: 1
Sent: 2
Sent: 3
Three received 1
Two received 2
Three received 3

Semphores and Message Passing

resource Sem()
	const N := 4
	var X := 0
	var Size := 1

	sem SafeX := Size





	process p(K:=1 to N)

		fa L := 1 to 2 ->
			P(SafeX)
			write("Safe", K)
			X := X + 1
			V(SafeX)
		af
	end
end

resource Sem()
	const N := 4
	var X := 0
	var Size := 1

	op SafeX() {send}
	fa K:= 1 to Size
		send SafeX()
	af 


	process p(K:=1 to N)

		fa L := 1 to 2 ->
			receive SafeX()
			write("Safe", K)
			X := X + 1
			send SafeX()
		af
	end
end



Too Many Messages
resource Message()
	op MyMessage(X: int)

	process one
		fa K := 1 to 5 -> send MyMessage(K) 
			write("Sent: ",K)
		af
	end

	process two
		var Answer: int

		fa J := 1 to 2 -> receive MyMessage(Answer)
			write("Two received ", Answer)
		af
	end
end

Sent: 1
Sent: 2
Sent: 3
Sent: 4
Sent: 5
Two received 1
Two received 2


Too Few Ears
resource Message()
	op MyMessage(X: int)

	process one

		fa K := 1 to 2 -> 
			send MyMessage(K) 
			write("Sent: ",K)
		af

	end


	process two
		var Answer: int

		fa J := 1 to 5 -> 
			receive MyMessage(Answer)
			write("Two received ", Answer)
		af

	end
end

Output
Sent: 1
Sent: 2
Two received 1
Two received 2
RTS warning: blocked process:Message.two : file message.sr, line 16
What is Wrong With This?


resource foo
	op bar(X: int) 

body foo(Me: char)
	var Answer: int

	receive bar(Answer)

	write(Me, " received ", Answer)

end foo

resource main()
	import foo

	var X: cap foo

	X := create foo('A')

	send X.bar(1) 
end


Messages to Resources

resource foo
	op bar(X: int) 

body foo(Me: char)

	process one
		var Answer: int

		receive bar(Answer)

		write(Me, " received ", Answer)

	end one

end foo
resource main()
	import foo

	var X: cap foo

	X := create foo('A')

	send X.bar(1) 
end

Deadlock?

resource Message()
	op MyMessage(X: int) 
	var Answer: int

	write("Start")  

	receive MyMessage(Answer)

	write("After receive") 
 
	send MyMessage(3)

	write("Send")   

	final
		write("The End")
	end
				      
end
Output

Start
The End
RTS warning: blocked process:Message.body : file message.sr, line 6


More Deadlock?

resource Message()
	op MyMessage(X: int) 

	process one
		var J: int

		write("Start one")
		receive MyMessage(J)
		write("End one")	
	end

	process two
		var Answer: int

		write("Start Two")
		receive MyMessage(Answer)
		write("End two")
	end

	final
		write("The End")
	end
				      
end

Output
Start one
Start Two
The End
RTS warning: blocked process:Message.two : file message.sr, line 15
RTS warning: blocked process: Message.one : file message.sr, line 8


Real Parallelism

resource hello
	op WhoAreYou()

body hello()

	external gethostname(res s: string[*];	
	                     nameLength: int)

	proc WhoAreYou()
		var HostName: string[32]

		gethostname(HostName, maxlength(HostName))

		write("Hello from ", HostName)
	end
end

resource main()
	import hello
	
	var NewSpace: cap vm

	NewSpace := create vm()

	#NewSpace := create vm() on "saturn"

	var X: cap hello

	X := create hello() on NewSpace

	X.WhoAreYou()
end

Using Multiple Workstations

resource hello
	op WhoAreYou()

body hello()
	external gethostname(res: s: string[*];	
	                     nameLength: int)

	proc WhoAreYou()
		var HostName: string[32]
		gethostname(HostName, maxlength(HostName))
		write("Hello from ", HostName)
	end
end

resource main
	import hello
	
	var A, B, C: cap vm

	locate(1,"ucssun1","~whitney/sr/a.out")
	locate(2,"atlas","~whitney/sr/a.out")

	A := create vm() on 1
	B := create vm() on 2

	var X, Y, Z: cap hello
	X := create hello() on A
	Y := create hello() on B
	Z := create hello() on A

	X.WhoAreYou()
	Y.WhoAreYou()
	Z.WhoAreYou()
end

Hello from ucssun1
Hello from atlas
Hello from ucssun1
Processes on Different Virtual Machines

resource foo
	op TestProc(How: string[20]) {send}

body foo()
	proc TestProc(How)
		fa k := 1 to 5 -> write(How) af
	end TestProc
	final 
		write("You killed me!")
	end
end foo
resource main()
	import foo
	var A, B: cap vm
	A := create vm() 
	B := create vm()
	
	var X, Y: cap foo
	X := create foo() on A
	Y := create foo() on B

	send X.TestProc("One")
	write("Sent One")
	send X.TestProc("Two")
	write("Sent Two")
	send Y.TestProc("Three")
	write("Sent Three")

	final
		write("All done")
		destroy A
	end
end    

Output
Sent One Sent Two Sent Three One Three One One Three Three One Three One Three Two Two Two Two Two All done You killed me!

Asynchronous Messages and VM


resource foo
	op bar(X: int) 

body foo(Me: char)
	process GetIt(P := 1 to 2)
		var Answer: int
		fa k := 1 to 2 -> 
			receive bar(Answer)
			write(P, Me, " received ", Answer)
		af
	end
end

resource main()
	import foo
	var Name[2]: char := ('A', 'B')
	var A[2]: cap vm
	var X[2]: cap foo

	fa K := 1 to 2 ->
		A[K] := create vm()
		X[K] := create foo(Name[K]) on A[K]
	af

	process fork(J := 1 to 2)
		fa K := 1 to 4 -> send X[J].bar(K) af
	end fork
end

1 A received 1
1 B received 1
2 B received 2
2 A received 2
1 A received 3
1 B received 3
2 B received 4
2 A received 4
Timing Saturn's Processors
Sequential Code

resource main()


	procedure worker(Amount: int)
		var Crap: real

		fa x := 1 to Amount,
		   y := 1 to Amount -> Crap := sin(x+y)
		af

	end worker

	var Amount: int; getarg(1,Amount)
	var Start: int := age()

	fa K := 1 to 4 -> worker(Amount) af

	final
		var End: int := age()
		write(End - Start)
	end
end

Timing Saturn's Processors
Processes


resource main()

	var Amount: int; getarg(1,Amount)
	var Start: int := age()

	process worker(K := 1 to 4)
		var Crap: real

		fa x := 1 to Amount,
		   y := 1 to Amount -> Crap := sin(x+y)
		af

	end worker

	final
		var End: int := age()
		write(End - Start)
	end
end

Timing Saturn's Processors
Virtual Machines
resource foo
	op worker(Amount: int) {send}

body foo()
	proc worker(Amount)
		var Crap: real

		fa x := 1 to Amount,
		   y := 1 to Amount -> Crap := sin(x+y)
		af
	end worker
end foo
resource main()
	import foo
	var A[4]: cap vm
	var X[4]: cap foo

	var Amount: int; getarg(1,Amount)
	var Start: int := age()

	fa K := 1 to 4 -> 
		A[K] := create vm() 
		X[K] := create foo() on A[K]
		send X[K].worker(Amount)
	af

	final
		var End: int := age()
		write(End - Start)
	end
end

Timing Saturn's Processors
Results

Amount                    Sequential  Process                 VM                      
100                              316  335                     995                     
150                              701  719                     926                     
200                             1237  1255                    1018                    
250                             1958  1975                    1250                    
300                             2865  2787                    1372                    
350                             3848  3809                    1752                    
400                             5126  4976                    1959                    
800                                                           9779                    


Remote Procedure Calls

A remote procedure requires creation of a new process, just to handle the procedure

If at all possible all procedure calls are treated as a normal procedure call, otherwise they are handled as a remote procedure call

resource CallMe
	op RealSoon(data: int)
body CallMe()
	proc RealSoon(data)
		write(data)
	end
end

resource main()
	import CallMe

	var Here: cap CallMe
	Here := create CallMe()
	Here.RealSoon(5)		#procedure call

	var RemoteIsland: cap vm
	var There: cap CallMe

	RemoteIsland:= create vm()
	There := create() CallMe on RemoteIsland
	
	There.RealSoon(5)		#remote procedure call

end

Return to Sender
resource main()
	op WhatIsThis(var A: int)   {call, send}

	proc WhatIsThis(A) 
		A := A + 1
		return
	end WhatIsThis

	var X: int := 0
	var Y: int := 0

	call WhatIsThis(X)
	send WhatIsThis(Y)

	write("X ", X, "Y ", Y)
end

Reply

resource main()
	op TryMe(var A: int) returns B: int

	proc TryMe(A) returns B
		A := 1
		B := 1

		reply

		nap(50)
		A := 20; B := 20
		write("Still Here")
	end


	var X: int := 0
	var Y: int := 0

	Y := TryMe(X)
	write(X, Y)				#prints 1 1
end

Why Reply?
resource converstion()
	op server(N: int) returns 
							c: cap (s: string[5])

	process client
		var Size: int := 8
		var t[Size]:string[5] := ([Size] "Hi")

		var c: cap (s: string[5])
		c := server(Size)
		fa K := 1 to Size -> send c(t[K]) af
	end

	proc server(N) returns c
		op line(s: string[5])
		c := line
		reply
		fa K := 1 to N ->
			var s: string[5]
			receive line(s)
			write(s)
		af
	end
end

Rendezvous

Input Statement
resource main()
	op f(x: int), g(u: int) returns v: int

	process p1
		var y: int := 5
		call f(y)
		write("p1")
	end

	process p2
		var w: int 
		w := g(10)
		write("p2 ", w)
	end

	process Q
		var z: int

		in f(x) -> z := x; write("f")
		[] g(u) returns v -> 
					z := u
					v := 8
					write("g")
		ni
		write("Q", z)
	end
end

Output
f
Q 5
p1


In and Send

resource main()
	op f(x: int), g(u: int)

	process p1
		send f(5)
		write("p1")
	end

	process p2
		send g(10)
		write("p2 ")
	end

	process Q
		var z: int

		in f(x) -> z := x; write("f")
		[] g(u) -> z := u; write("g")
		ni
	
		write("Q", z)
	end
end

Output
p1
p2
f
Q 5
Peeking at the Message Queue
resource main()
	op foo(x: int), bar(y: int)

	process one
		nap(500)
		send foo(5)
	end

	process two
		var it: int
		in foo(p) -> it := p
		[] bar(p) -> it := p
		[] else -> write("no message")
		ni
	end

end

Output

no message


Receive Expanded
resource Message()
	op it(X: int)

	process one
		send it(3) 
	end

	process two
		var X: int

		receive it(X)


		write(X)
	end
		
end

resource Message()
	op it(X: int)

	process one
		send it(3) 
	end

	process two
		var X: int

		in it(P) -> X :=P
		ni

		write(X)
	end
		
end

Message Passing Reviewed

Asychronous Message Passing
op it(X: real)
op what(X: int)
process one

	send it(2.5)

end

process two
	var Y: real
	in it(w) -> Y := w
	ni
end

process three

	send what(2)

end

process four
	var Y: int
	receive what(Y)
end

Sychronous Message Passing
op it(X: real)
op what(X: int)
process one

	call it(2.5)

end

process two
	var Y: real
	in it(w) -> Y := w
	ni
end

process three

	call what(2)

end

process four
	var Y: int
	receive what(Y)
end


Synchronization Expressions

resource main()
	op a(z: int)
	op b(a: int, b: int)
	var C: int

	process one
		var X: int
		read(X); 
		send a(X);  send b(3,X)
	end one

	process two
		in a(x) st C > 0 -> write("2, C>0")
		ni
	end two

	process three
		in a(x) st x < 0 -> write("3, X<0")
		ni
	end

	process four
		in a(x) st x = 12 -> write("4, 12")
		[] b(y,z) st y = sin(x) ->write("b")
		ni
	end

	process five
		var x: int
		if ?a > 0 -> receive a(x)
		fi
	end
end

Scheduling Expressions
resource main()
	op a(x: int)

	fa K := 4 downto 1 -> send a(K) af

	do ?a > 0 -> 
		in a(x) by x -> write(x) ni
	od
end

Output
1
2
3
4
resource main()
	op a(x: int)

	fa K := 1 to 4 -> send a(K) af

	fa K := 1 to 4 ->
		in a(x) st  x mod 2 = 0 by -x ->
								 write(K, x) 
		[] else -> write(K, "No go")
		ni
	af
end

1 4
2 2
3 No go
4 No go