Threading Questions

Steven Schveighoffer via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Tue Sep 29 12:10:58 PDT 2015


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


More information about the Digitalmars-d-learn mailing list