Thread overview
Thread synchronization
Nov 30, 2006
JohnC
Nov 30, 2006
Sean Kelly
Nov 30, 2006
xs0
Jan 03, 2007
Matthew Wesley
Jan 03, 2007
Sean Kelly
November 30, 2006
What's the recommended way to guard static variables?

1) synchronized by itself?

  static Object getObj() {
    synchronized {
      return sharedVar;
    }
  }

2) synchronized on classinfo?

  static Object getObj() {
    synchronized (typeof(sharedVar).classinfo) {
      return sharedVar;
    }
  }

3) synchronized on a static Object instance?

  static this() {
    syncLock = new Object;
  }

  static Object getObj() {
    synchronized (syncLock) {
      return sharedVar;
    }
  }

I've seen all these patterns used. Are they all safe?

Cheers,
John.


November 30, 2006
JohnC wrote:
> What's the recommended way to guard static variables?
> 
> 1) synchronized by itself?
> 
>   static Object getObj() {
>     synchronized {
>       return sharedVar;
>     }
>   }
> 
> 2) synchronized on classinfo?
> 
>   static Object getObj() {
>     synchronized (typeof(sharedVar).classinfo) {
>       return sharedVar;
>     }
>   }
> 
> 3) synchronized on a static Object instance?
> 
>   static this() {
>     syncLock = new Object;
>   }
> 
>   static Object getObj() {
>     synchronized (syncLock) {
>       return sharedVar;
>     }
>   }
> 
> I've seen all these patterns used. Are they all safe?

They're all safe.  Since #1 is in a static method, it will synchronize on the ClassInfo object, just like you're doing manually in #2.  And #3 just specifies a separate static object on which to synchronize.  But since it's static, you'll get the same effect.


Sean
November 30, 2006
Sean Kelly wrote:
> JohnC wrote:
>> What's the recommended way to guard static variables?
>>
>> 1) synchronized by itself?
>>
>>   static Object getObj() {
>>     synchronized {
>>       return sharedVar;
>>     }
>>   }
>>
>> 2) synchronized on classinfo?
>>
>>   static Object getObj() {
>>     synchronized (typeof(sharedVar).classinfo) {
>>       return sharedVar;
>>     }
>>   }
>>
>> 3) synchronized on a static Object instance?
>>
>>   static this() {
>>     syncLock = new Object;
>>   }
>>
>>   static Object getObj() {
>>     synchronized (syncLock) {
>>       return sharedVar;
>>     }
>>   }
>>
>> I've seen all these patterns used. Are they all safe?
> 
> They're all safe.  Since #1 is in a static method, it will synchronize on the ClassInfo object, just like you're doing manually in #2.  And #3 just specifies a separate static object on which to synchronize.  But since it's static, you'll get the same effect.

I think the first one synchronizes only on the statement itself, so while only one getObj can execute concurrently, it doesn't guard against a similar setObj()..

xs0
January 03, 2007
On Thu, 30 Nov 2006 13:04:48 +0100
xs0 <xs0@xs0.com> wrote:

> Sean Kelly wrote:
> > JohnC wrote:
> >> What's the recommended way to guard static variables?
> >>
> >> 1) synchronized by itself?
> >>
> >>   static Object getObj() {
> >>     synchronized {
> >>       return sharedVar;
> >>     }
> >>   }
> >>
> >> 2) synchronized on classinfo?
> >>
> >>   static Object getObj() {
> >>     synchronized (typeof(sharedVar).classinfo) {
> >>       return sharedVar;
> >>     }
> >>   }
> >>
> >> 3) synchronized on a static Object instance?
> >>
> >>   static this() {
> >>     syncLock = new Object;
> >>   }
> >>
> >>   static Object getObj() {
> >>     synchronized (syncLock) {
> >>       return sharedVar;
> >>     }
> >>   }
> >>
> >> I've seen all these patterns used. Are they all safe?
> > 
> > They're all safe.  Since #1 is in a static method, it will synchronize on the ClassInfo object, just like you're doing manually in #2.  And #3 just specifies a separate static object on which to synchronize.  But since it's static, you'll get the same effect.
> 
> I think the first one synchronizes only on the statement itself, so while only one getObj can execute concurrently, it doesn't guard against a similar setObj()..
> 
> xs0

Perhaps I am misunderstanding the synchronized specification, as none of these methods seem safe to me. When I read that "Synchronized allows only one thread at a time to execute ScopeStatement" from http://www.digitalmars.com/d/statement.html#SynchronizedStatement, that seems to me that only the return statement is protected in any of these cases, while any modification of the returned object is unsynchronized.

This seems to be what xs0 mentions above about #1, but how are #2 and #3 any different?

On a related note,, the specification says that "where Expression evaluates to an Object reference, allows only one thread at a time to use that Object to execute the ScopeStatement." Doesn't this mean that there is no way to synchronize separate critical sections? For example, two or more critical sections that would block on the same mutex in a C environment.
January 03, 2007
Matthew Wesley wrote:
> On Thu, 30 Nov 2006 13:04:48 +0100
> xs0 <xs0@xs0.com> wrote:
> 
>> Sean Kelly wrote:
>>> JohnC wrote:
>>>> What's the recommended way to guard static variables?
>>>>
>>>> 1) synchronized by itself?
>>>>
>>>>   static Object getObj() {
>>>>     synchronized {
>>>>       return sharedVar;
>>>>     }
>>>>   }
>>>>
>>>> 2) synchronized on classinfo?
>>>>
>>>>   static Object getObj() {
>>>>     synchronized (typeof(sharedVar).classinfo) {
>>>>       return sharedVar;
>>>>     }
>>>>   }
>>>>
>>>> 3) synchronized on a static Object instance?
>>>>
>>>>   static this() {
>>>>     syncLock = new Object;
>>>>   }
>>>>
>>>>   static Object getObj() {
>>>>     synchronized (syncLock) {
>>>>       return sharedVar;
>>>>     }
>>>>   }
>>>>
>>>> I've seen all these patterns used. Are they all safe?
>>> They're all safe.  Since #1 is in a static method, it will
>>> synchronize on the ClassInfo object, just like you're doing
>>> manually in #2.  And #3 just specifies a separate static object on
>>> which to synchronize.  But since it's static, you'll get the same
>>> effect.
>> I think the first one synchronizes only on the statement itself, so while only one getObj can execute concurrently, it doesn't guard
>> against a similar setObj()..
>>
>> xs0
> 
> Perhaps I am misunderstanding the synchronized specification, as none
> of these methods seem safe to me. When I read that "Synchronized allows
> only one thread at a time to execute ScopeStatement" from
> http://www.digitalmars.com/d/statement.html#SynchronizedStatement, that
> seems to me that only the return statement is protected in any of these
> cases, while any modification of the returned object is unsynchronized.

This is correct.  Given:

    synchronized(obj) { ... }

You can consider the opening brace of the synchronized block to be equivalent to a mutex lock operation where obj is the mutex being locked.  Exiting the scope of a synchronized block by any means releases the lock.

> This seems to be what xs0 mentions above about #1, but how are #2 and
> #3 any different?

In #1, the mutex being used is implicit while in #2 and #3 it's explicit.  In all cases however, the programmer is responsible for locking all related functions on the proper object.

> On a related note,, the specification says that "where Expression
> evaluates to an Object reference, allows only one thread at a time to
> use that Object to execute the ScopeStatement." Doesn't this mean that
> there is no way to synchronize separate critical sections? For example,
> two or more critical sections that would block on the same mutex in a C
> environment.

Well, these two functions lock on the same mutex:

    class C
    {
        void f1()
        {
            synchronized
            {
                ...
            }
        }

        void f2()
        {
            synchronized
            {
                ...
            }
        }

        static void f3()
        {
            synchronized
            {
                ...
            }
        }

        static void f4()
        {
            synchronized
            {
                ...
            }
        }
    }

    C val = new C;
    // f1 and f2 are mutually exclusive
    val.f1();
    val.f2();
    // f3 and f4 are mutually exclusive
    val.f3();
    val.f4();

In this case, the mutex used for f1 and f2 is the object monitor for val, while the mutex used for f3 and f4 is the object monitor for C. This is equivalent to:

    class C
    {
        Object lock;
        static Object s_lock;

        this()
        {
            lock = new Object;
        }

        static this()
        {
            s_lock = new Object;
        }

        void f1()
        {
            synchronized(lock)
            {
                ...
            }
        }

        void f2()
        {
            synchronized(lock)
            {
                ...
            }
        }

        static void f3()
        {
            synchronized(s_lock)
            {
                ...
            }
        }

        static void f4()
        {
            synchronized(s_lock)
            {
                ...
            }
        }
    }

    C val = new C;
    // f1 and f2 are mutually exclusive
    val.f1();
    val.f2();
    // f3 and f4 are mutually exclusive
    val.f3();
    val.f4();

Does that help?


Sean