On 9/25/15 11:19 AM, bitwise wrote:
Hey, I've got a few questions if anybody's got a minute.

I'm trying to wrap my head around the threading situation in D. So far,
things seem to be working as expected, but I want to verify my solutions.

1) Are the following two snippets exactly equivalent(not just in
observable behaviour)?
a)

Mutex mut;
mut.lock();
scope(exit) mut.unlock();

b)
Mutex mut;
synchronized(mut) { }

Will 'synchronized' call 'lock' on the Mutex, or do something
else(possibly related to the interface Object.Monitor)?

Yes. A mutex object has it's internal lock as its monitor.

2) Phobos has 'Condition' which takes a Mutex in the constructor. The
documentation doesn't exactly specify this, but should I assume it works
the same as std::condition_variable in C++?

I am not sure about std::condition_variable. core.sync.condition works like a standard condition (https://en.wikipedia.org/wiki/Monitor_%28synchronization%29)

For example, is this correct?

Mutex mut;
Condition cond = new Condition(mut);

// mut must be locked before calling Condition.wait
synchronized(mut)  // depends on answer to (1)
{
     // wait() unlocks the mutex and enters wait state
     // wait() must re-acquire the mutex before returning when cond is
signalled
     cond.wait();
}

Yes, I believe it is.

3) Why do I have to pass a "Mutex" to "Condition"? Why can't I just pass
an "Object"?

An object that implements the Monitor interface may not actually be a mutex. For example, a pthread_cond_t requires a pthread_mutex_t to operate properly. If you passed it anything that can act like a lock, it won't work. So the Condition needs to know that it has an actual Mutex, not just any lock-like object.

I think I advocated in the past to Sean that Condition should provide a default ctor that just constructs a mutex, but it doesn't look like that was done.


4) Will D's Condition ever experience spurious wakeups?

What do you mean by "spurious"? If you notify a condition, anything that is waiting on it can be woken up. Since the condition itself is user defined, there is no way for the actual Condition to verify you will only be woken up when it is satisfied.

In terms of whether a condition could be woken when notify *isn't* called, I suppose it's possible (perhaps interrupted by a signal?). But I don't know why it would matter -- per above you should already be checking the condition while within the lock.

I think there are cases with multiple threads where you can potentially wake up the thread waiting on a condition AFTER the condition was already reset by another.

5) Why doesn't D's Condition.wait take a predicate? I assume this is
because the answer to (4) is no.

The actual "condition" that you are waiting on is up to you to check/define.

6) Does 'shared' actually have any effect on non-global variables beside
the syntactic regulations?

I believe shared doesn't alter code generation at all. It only prevents certain things and affects the type.

I know that all global variables are TLS unless explicitly marked as
'shared', but someone once told me something about 'shared' affecting
member variables in that accessing them from a separate thread would
return T.init instead of the actual value... or something like that.
This seems to be wrong(thankfully).

No, this isn't true.

For example, I have created this simple Worker class which seems to work
fine without a 'shared' keyword in sight(thankfully). I'm wondering
though, if there would be any unexpected consequences of doing things
this way.

http://dpaste.com/2ZG2QZV

Some errors:

1. When calling notifyAll, you should ALWAYS have the mutex locked.
2. Since the mutex is protecting _run, it should only be checked/modified with the lock held. 3. After you have been woken up, you should check that the condition is satisfied. 4. Technically, you shouldn't access member variables that are GC allocated from a dtor. I know it's a struct, but structs can be GC allocated as well.

I would replace your if(tasks.empty) with while(tasks.empty && _run) to fix issue 3.

-Steve

Reply via email to