[dmd-concurrency] What is protected by synchronization?

Robert Jacques sandford at jhu.edu
Sat Jan 30 14:25:15 PST 2010


On Sat, 30 Jan 2010 15:30:04 -0500, Michel Fortin  
<michel.fortin at michelf.com> wrote:

> Le 2010-01-30 à 9:57, Michel Fortin a écrit :
>
>> Since we're talking about synchronization again, I think this is a  
>> problem that should be addressed.
>
> (Replying to myself)
>
> Robert's comment in the other thread makes me realize I've skipped over  
> something important in my previous message: fields inside a synchronized  
> object shouldn't 'shared'. Despite being usable from many threads due to  
> synchronization, they behave much more like thread-local fields where  
> the thread they belong to changes depending on who holds the lock.

I assume this is only for value types and not references.

> So what I'm proposing is that a synchronized object contains non-shared  
> fields unless explicitly marked shared. Those fields wouldn't be  
> accessible from anywhere except inside a synchronized block. Inside a  
> synchronized block they are accessible and treated as thread-local.

Except shared functions can return thread-local objects, which will cause  
escapes in the model. And class instance A could give references to class  
instance B, resulting in an escape.

> The only thing lacking is a way to avoid them from escaping when passing  
> them to functions. If we deem it necessary, we could add a type modifier  
> for that (although it probably won't enough by itself).

The type modifier you are looking for is called 'owned'. Bartosz went into  
some detail of it on his blog. From a runtime perspective, owned objects  
are all protected by a common mutex, and are therefore shared objects.  
 From a compile time perspective, it provides the ability to optimize away  
some recursive locks, etc.

> But as long as the programmer doesn't let those references escape,  
> things will run smoothly. I think having fined-grained controls over  
> what is protected by the lock and what will use atomic operations is a  
> necessity if you want to achieve decent performances.
>
> More examples:
>
> 	synchronized class SyncObject {
> 		shared(int)*[] data;
> 		// only the last part can be shared,
> 		// the rest is protected by the object's lock.
>
> 		SyncObject next;
> 		// the reference is protected by the object's lock,
> 		// but the object itself can be shared since it is synchronized.
>
> 		char[] buffer;
> 		// the whole thing is protected by the object's lock.
>
> 		SomeStruct s;
> 		// s.a is protected by the object's lock.
> 		// s.b is shared as per struct's definition.
> 		// s.test() is callable under the object's lock.
> 	}
>
> 	struct SomeStruct {
> 		int a;
> 		shared(int) b;
>
> 		void test() {
> 			a += 1;
> 			b += 1; // this one is always atomic.
> 		}
> 	}
>
>



More information about the dmd-concurrency mailing list