On 2012-06-04 13:15:57 +0000, "Jason House" <[email protected]> said:
The example about current D seems a bit lacking. You change behavior
because it's easy to code a different way. If you really want to use
synchronized classes, then you should have two of them. The map can be
in one synchronized class and the counters can be in another. the main
class in the example would simply call methods on the synchronized
objects.
Valid comment. I thought about creating yet another example
illustrating that, but I gave up when realizing the silliness of it. I
mean, yes you can make it work, but at the price of writing a lot of
boilerplate code just for forwarding things around.
Here's a modified implementation of that dictionary class, wrapping the
translations AA and the two counters in two distinct classes:
class Dictionary
{
private SynchronizedStringMap translations;
private SynchronizedCounters counters;
void addWord(string word, string foreignWord)
{
synchronized(translations)
{
translations[word] = foreignWord;
counters.addUnconfirmed();
}
}
bool confirmWord(string word, string foreignWord)
{
synchronized(translations)
{
string * found = word in translation;
if (!found)
return false;
if (*found != foreignWord)
return false;
}
synchronized(counters)
{
counters.removeUnconfirmed();
counters.addConfirmed();
}
globalNotifyWordConfirmed(word, foreignWord);
return true;
}
}
That done, I still have to implement two other classes:
SynchronizedStringMap which needs to implement the '[]' and 'in'
operators, and counters which needs to implement addUnconfirmed, and
SynchronizedCounters which needs to implement addUnconfirmed,
removeUnconfirmed, and addConfirmed. All those functions just
forwarding calls to the wrapped variable(s). And all this for a simple
toy example.
That said, the other point is that it's too easy to shoot yourself in
the foot using implicit synchronization. It's easy to forget you still
have a mutex locked when adding the call to globalNotifyWordConfirmed,
especially if you add this line of code later in the development
process and you have forgotten about the "synchronized" keyword far
away at the very top of the class declaration. And once you have a
deadlock and you've identified the culprit, to fix the bug you need to
split everything that needs to be synchronized into a separate class, a
tiresome and bug-prone process, just because you can't opt-out of the
implicit synchronization. Call me nuts if you want, but I think this is
awful.
That being said, I've never used synchronized classes in my
multithreaded D1/D2 code. I used Tango's Mutexes and Conditions.
They're more flexible.
I'd say it's a good choice. How does it work with shared variables in
D2, or are you just ignoring the type system?
--
Michel Fortin
[email protected]
http://michelf.com/