Directory
General Information |
Schedule and Readings |
Assignments |
Announcements
A Concurrent ML example
This program implements the concurrent-read-exclusive-write (CRXW)
lock covered in lecture. To run this program, make a directory containing
the two file
Run "sml" version 110.0.3 or 110.9.1 (i.e., /usr/local/sml/bin/sml),
type CM.make(); at the first prompt, then
Test.go(); at the next prompt.
It will run indefinitely, though you may stop it with an interrupt
(control-C).
The sml file contains two separate implementations of the CRXW lock;
one in which the locking operations are functions and one in which
they are events. The first one is a bit simpler to understand;
the second one gives the client a bit more choice about blocking.
Notes on CML programming:
- Contrary to what I may have said in class or what is in Harper's
slides, use sml to run a CML program, not cml-cm.
- Any creation of a channel, sync on an event, etc. must occur within
a call to RunCML.doit(). Thus, for example, in structure Test
the code
local val randCh : int chan = channel()
fun loop s = (send(randCh, s mod 10);
loop((s+37) mod 61))
val _ = spawnc loop 0
in fun random() = recv randCh
end
is not at top level in the structure, but is put inside the
main function. Reppy's book, page 75, footnote 2, mentions
this fact, but unfortunately refers to the not-yet-available
CML Reference Manual for an explanation.
- The ordinary TextIO library won't work for CML, since two different
threads should not access the same queue without synchronization.
Therefore CML provides its own TextIO library with a similar interface,
and you can just use print(s) to print a string s.
However, because of a bug in the compilation manager, it is helpful
to have the line structure TextIO=TextIO in the beginning of
any sml file that mentions print.
- When you call RunCML.doit it will not return as long as
any thread can execute. When all the threads have exited or deadlocked,
then RunCML.doit will return. This is different from the
behavior of java, which stops as soon as the original thread
returns, no matter how many other threads it may have spawned that
are still running.
- This program uses guard and withNack
as explained in a separate note.
Therefore, the last line of Test.main, which reads
app (sync o joinEvt) threads
is not really necessary. But I left it in to illustrate the management
of thread id's.