(2) CAPE should be coming today to do their evaluation.
(3) From the Engineering Student Services Staff: It's not too late to sign up for the 2002 JACOBS SCHOOL OF ENGINEERING GRADUATION and RECOGNITION BANQUET! We've extended the reservation deadline to Monday, June 10, 2002.
When: Saturday, June 15, 2002, 6:00pm (Reception), 7:00pm (Dinner &
Program)
Where: San Diego Marriott-La Jolla
Cost: $15/student/faculty/staff, $25/guest
Make your reservation on-line now at http://www.jacobsschool.ucsd.edu/ESS/GradBanquet/
or come to the Engineering Student Services Office at EBU-I, Room 1400
(Open M-F, 8-12pm & 1-4:30pm). For more information Call (858) 534-6105
or Email: gradbanquet@soe.ucsd.edu.
Practical programming languages use call-by-environment, but call-by-macro is theoretically important because
Consider the pseudo-Pascal summation function using call-by-macro from before. This can be implemented using call-by-value with function arguments:
The lesson to learn here is that higher-order functions give the functionality of call-by-macro.function sum (lo,hi:int; ref k:int; f:void->real);
var s: real := 0;
begin
for k := lo to hi do s := s + f();
return s
end;function f(): real;
begin
return a[j]*b[j];
end;
Processes have state: the values stored in the CPU registers, plus perhaps memory. Changing between processes is expensive because the state of one process has to be saved and the state of another has to be restored.
A "thread" is a lightweight process, i.e. one with only a small amount of state that needs to be saved and restored. Advantage: switching between lightweight processes is fast. The definition used by many authors is that each process has its own address space, while threads share memory, i.e. share one address space.
We'll look at tasks in Ada to show how how a process can be made similar
to other high-level programming constructs.
A task is like an object and an entry is like a method for an object. Entries can have "in" and "out" parameters.
A task body consists of code that can "accept" entry calls at certain times during execution. The code below can only accept a "take" immediately after accepting a "give":task buffer is
entry give (x: in item);
entry take (x: out item);
end buffer;
task body buffer is
it: item;
begin
loop
accept give (x: in item) do
it := x;
end give;
accept take (x: out item) do
x := it;
end take;
end loop;
end buffer;
Remember that in Ada, a task specification looks like an abstract type (ADT) specification. The outside world (i.e. any other task) interacts with a task by calling its "entries".
Note that "off by one" mistakes are easy in the code above. Ada helps in detecting these mistakes by allowing precise, explicit subranges for integer variables.task body buffer is
size: constant integer := 10;
b: array (1..size) of item;
n: integer range 0..size := 0;
inloc, outloc: integer range 1..size := 1;
begin
loop
select
when n < size =>
accept give (x: in item) do
b(inloc) := x;
end give;
n := n+1;
inloc := (inloc mod size) + 1;
or when n > 0 =>
accept take (x: out item) do
x := b(outloc);
end take;
n := n-1;
outloc := (outloc mod size) + 1;
end select;
end loop;
end buffer;
Synchronization means reaching the same point at the same time. One thread must do a "send" at the same time (or immediately before) the other does a "receive".
An Ada rendezvous is like a telephone call: during the rendezvous the caller and the callee are synchronized. The caller chooses the callee and knows which task this is. The callee does not know who the caller is.
A caller can be a hardware interrupt or a trap (i.e. an interrupt generated by low-level software).
Execution of the caller of an entry is suspended while the callee is executing code between the accept line and the corresponding end.
"Mutual exclusion" means that only one thread at a time can have access
to a resource. Concurrent programming always involves mutual exclusion.
Mutual exclusion can be guaranteed if a resource is only manipulated inside
accept
blocks.
Note that in Ada pointers are dereferenced automatically when this makes sense from the syntactic context.task type printer is
entry init(id: string);
entry print(s: string);
end printer;task body printer is
...
begin
accept init(id: string) do
...
end init;
...
end printer;type printerptr is access printer;
p := new printer; p.init("123.456.000.000");
q := new printer;
As a high-level approach to parallel programming, it is not clear how to implement Ada tasking very efficiently. On different computers, the most efficient implementation method may be very different.With message passing, threads send and receive data. Note that the word "message" here does not imply all of object-oriented programming. Sending is like writing, and receiving is like reading. With shared memory, two (or more threads) use the same variable. To communicate, one thread assigns a new value to a variable, and another thread uses the value of the variable.
In general, message-passing can be implemented using shared memory: first the sender sets the value of a variable to be the message, then the receiver uses the variable.
Conversely, shared memory can be simulated using message-passing, with
a third thread.
An operation is called atomic if it is guaranteed to be performed "all or nothing", i.e. with mutual exclusion.
Typically the most primitive concurrent programming operation, implemented in hardware, is "test and set". In pseudo-code this operation on a shared register X is
"Test and set" is implemented by the CPU in hardware to be atomic. It can be used to build more complicated atomic operations.if X == 0 then { X := 1; return 0 }
else return 1
If the database system guarantees that a piece of code labeled as a transaction has the atomic, isolated, and durable properties. The program chooses which pieces of code are large enough to be considered consistent. S/he encloises these blocks with keywords like begin and commit. Anywhere inside the block the programmer can write rollback.Atomic Consistent Isolated Durable
See The
four ACID properties by Jim Gray.
Copyright (c) 2002 by Charles Elkan.