|
Boost : |
From: Gregory Seidman (gseidman_at_[hidden])
Date: 2000-10-23 15:25:10
A friend of mine handed me the minutes of the 10/22 meeting because I had
been telling him about having implemented monitors in C++ (trying to have
the convenience of Java's synchronization primitives). I have attached my
implementation to this message.
I want to make it clear that this was primarily implemented for my own
convenience. It is only because of the simplicity of the design and code
that I consider it reasonable to inflict on you as is. Note also that there
are numerous optimizations to be implemented. I am hoping that this will be
considered a starting point; I am not presenting it as finished code for
public consumption. I am releasing this code to the public domain. No
rights reserved (though I'd kind of like some credit for it somewhere, I
will not legally require it).
TODO:
port to other threading libraries (win32, etc.)
currently POSIX only
efficient allocator for Monitor::Token
relies on auto_ptr, thus new and delete
improve recursive locking
each recursive lock is two pthread calls
add various runtime options
size of initial Token memory pool
tradeoff between lock speed and condition wait speed
recursion on or off
revise preprocessor macros
do something smarter with Monitor destruction
namespace changes
improve or remove Synchronizable convenience class
I assume most everyone is familiar with the concept of monitors. The way
one uses this implementation is as follows (playing fast and loose with
namespaces):
class SomeClass {
private:
Monitor *mon, *othermon;
public:
SomeClass() : mon(new Monitor()), othermon(new Monitor()) { }
~SomeClass() {
while (!(
Monitor::destroyMonitor(mon) &&
Monitor::destroyMonitor(othermon)
));
}
void synchronizedMethod();
};
void
SomeClass::synchronizedMethod() {
MONITOR_SYNCHRONIZE_BLOCK(mon);
//...early return
if (early)
return;
//...recursive call
if (notdone)
synchronizedMethod();
//...synchronizing a subblock
if (otherthing) {
MONITOR_SYNCHRONIZE_BLOCK(othermon);
//...
}
//...exception
if (exceptional)
throw foo;
//...normal exit
}
The locking occurs upon allocation of a Monitor::Token and unlocking occurs
when that token is deleted. By enclosing the token in an auto_ptr we
guarantee that however the stack is unwound (exception, early return,
whatever) as soon as the token is out of scope the monitor is unlocked. The
monitor is currently recursive (i.e. once in code protected by the monitor
the program can call any other code protected by the same monitor) and
works around the problem with recursive POSIX mutexes and conditional
waiting (only unlocking the recursive mutex once instead of completely).
Note that, like any other synchronization system, it is still possible to
deadlock in all the usual ways.
--Greg
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk