More synchronized ideas
Jason House
jason.james.house at gmail.com
Mon Jun 4 18:58:04 PDT 2012
On Monday, 4 June 2012 at 17:40:38 UTC, Michel Fortin wrote:
> On 2012-06-04 13:15:57 +0000, "Jason House"
> <jason.james.house at gmail.com> said:
>
>> If you really want to use synchronized classes, then you should
>> have two of them.
>
> 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:
>
> ...
>
> 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.
I was thinking something more like this:
shared class Dictionary
{
private SynchronizedCounters counters;
private SynchronizedStringMap translations(counters);
void addWord(string word, string foreignWord) shared
{
// synchronized opIndexAssign call
translations[word] = foreignWord;
}
bool confirmWord(string word, string foreignWord) shared
{
// synchronized opIndex call
string candidate = translations[word];
if (candidate != foreignWord)
return false;
counters.confirmOneWord();
globalNotifyWordConfirmed(word, foreignWord);
return true;
}
}
// All counter operations are embedded here
// No need to review for any unsafe data usage,
// it's all here (future uses will add new methods)
synchronized class SynchronizedCounters
{
private int confirmed, unconfirmed;
void addUnconfirmed() { ++unconfirmed; }
void confirmOneWord() { --unconfirmed; ++confirmed; }
}
// Similar concept, but embeds SynchronizedCounters
// I don't like that, but it's the only way to fully
// embrace D synchronized classes for toy example
synchronized class SynchronizedStringMap
{
private string[string] translations;
private SynchronizedCounters counters;
this(SynchronizedCounters _counters)
: counters(_counters) {}
void opIndexAssign(string word, string foreignWord)
{
translations[word] = foreignWord;
counters.addUnconfirmed();
}
string opIndex(string word)
{
shared string *found = word in translations;
if (found)
return *found;
else
return null;
}
}
>
>
>> 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?
I did not find my mutex based code, but did find a lock free
broadcast queue. It was written to be shared-aware. Here's the
receive class:
/// Receives delegates from the specified sender. Never blocks.
class receiver{
private target parent;
private shared sender source;
private int nextMessageId = 1;
this(target t, shared sender s){ parent = t; source = s; }
bool receive(){
if (source.receive(nextMessageId, parent)){
nextMessageId++;
return true;
}
return false;
}
}
And here was the receive method in the sender class:
private bool receive(int messageId, target t) shared
{
if (pending == 0 || id < messageId)
return false;
msg(t);
atomicDecrement!(msync.raw)(pending);
return true;
}
atomicDecrement in Tango was a template. Looking at the commit
logs, it looks like I had to hack at isValidNumericType, but I
did not have to change the Atomic.d (beyond removing the volatile
keywords and fixing incorrect assembly)
More information about the Digitalmars-d
mailing list