Something needs to happen with shared, and soon.

luka8088 luka8088 at owave.net
Mon Nov 12 15:25:16 PST 2012


Here i as wild idea:

//////////

void main () {

   mutex x;
   // mutex is not a type but rather a keyword
   // x is a symbol in order to allow
   // different x in different scopes

   shared(x) int i;
   // ... or maybe use UDA ?
   // mutex x must be locked
   // in order to change i

   synchronized (x) {
     // lock x in a compiler-aware way
     i++;
     // compiler guarantees that i will not
     // be changed outside synchronized(x)
   }

}

//////////

so I tried something similar with current implementation:

//////////

import std.stdio;

void main () {

   shared(int) i1;
   auto m1 = new MyMutex();

   i1.attachMutex(m1);
   // m1 must be locked in order to modify i1
	
   // i1++;
   // should throw a compiler error

   // sharedAccess(i1)++;
   // runtime exception, m1 is not locked

   synchronized (m1) {
     sharedAccess(i1)++;
     // ok, m1 is locked
   }

}

// some generic code

import core.sync.mutex;

class MyMutex : Mutex {
   @property bool locked = false;
   @trusted void lock () {
     super.lock();
     locked = true;
   }
   @trusted void unlock () {
     locked = false;
     super.unlock();
   }
   bool tryLock () {
     bool result = super.tryLock();
     if (result)
       locked = true;
     return result;
   }
}

template unshared (T : shared(T)) {
   alias T unshared;
}

template unshared (T : shared(T)*) {
   alias T* unshared;
}

auto ref sharedAccess (T) (ref T value) {
   assert(value.attachMutex().locked);
   unshared!(T)* refVal = (cast(unshared!(T*)) &value);
   return *refVal;
}

MyMutex attachMutex (T) (T value, MyMutex mutex = null) {
   static __gshared MyMutex[T] mutexes;
   // this memory leak can be solved
   // but it's left like this to make the code simple
   synchronized if (value !in mutexes && mutex !is null)
     mutexes[value] = mutex;
   assert(mutexes[value] !is null);
   return mutexes[value];
}

//////////

and another example with methods:

//////////

import std.stdio;

class a {
   int i;
   void increment () { i++; }
}

void main () {

   auto a1 = new shared(a);
   auto m1 = new MyMutex();

   a1.attachMutex(m1);
   // m1 must be locked in order to modify a1
	
   // a1.increment();
   // compiler error

   // sharedAccess(a1).increment();
   // runtime exception, m1 is not locked

   synchronized (m1) {
     sharedAccess(a1).increment();
     // ok, m1 is locked
   }

}

// some generic code

import core.sync.mutex;

class MyMutex : Mutex {
   @property bool locked = false;
   @trusted void lock () {
     super.lock();
     locked = true;
   }
   @trusted void unlock () {
     locked = false;
     super.unlock();
   }
   bool tryLock () {
     bool result = super.tryLock();
     if (result)
       locked = true;
     return result;
   }
}

template unshared (T : shared(T)) {
   alias T unshared;
}

template unshared (T : shared(T)*) {
   alias T* unshared;
}

auto ref sharedAccess (T) (ref T value) {
   assert(value.attachMutex().locked);
   unshared!(T)* refVal = (cast(unshared!(T*)) &value);
   return *refVal;
}

MyMutex attachMutex (T) (T value, MyMutex mutex = null) {
   static __gshared MyMutex[T] mutexes;
   // this memory leak can be solved
   // but it's left like this to make the code simple
   synchronized if (value !in mutexes && mutex !is null)
     mutexes[value] = mutex;
   assert(mutexes[value] !is null);
   return mutexes[value];
}

//////////

In any case, if shared itself does not provide locking and does not 
fixes problems but only points them out (not to be misunderstood, I 
completely agree with that) then I think that assigning a mutex to the 
variable is a must.

Aldo latter examples already work with current implementation I like the 
first one (or something similar to the first one) more, it looks cleaner 
and leaves space for additional optimizations.


On 12.11.2012 17:14, deadalnix wrote:
> Le 12/11/2012 16:00, luka8088 a écrit :
>> If I understood correctly there is no reason why this should not
>> compile ?
>>
>> import core.sync.mutex;
>>
>> class MyClass {
>> void method () {}
>> }
>>
>> void main () {
>> auto myObject = new shared(MyClass);
>> synchronized (myObject) {
>> myObject.method();
>> }
>> }
>>
>
> D has no ownership, so the compiler can't know what
> if it is safe to do so or not.



More information about the Digitalmars-d mailing list