www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Thread synchronization

reply "JohnC" <johnch_atms hotmail.com> writes:
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. 
Nov 29 2006
next sibling parent reply Sean Kelly <sean f4.ca> writes:
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
Nov 29 2006
parent reply xs0 <xs0 xs0.com> writes:
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
Nov 30 2006
parent Sean Kelly <sean f4.ca> writes:
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?

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.

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
Jan 03 2007
prev sibling parent Matthew Wesley <mppw carolina.rr.com> writes:
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.
Jan 03 2007