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