On 10/7/20 20:30, mw wrote:
On Friday, 10 July 2020 at 17:35:56 UTC, Steven Schveighoffer wrote:
Mark your setTime as shared, then cast away shared (as you don't need
atomics once it's locked), and assign:
synchronized setTime(ref SysTime t) shared {
(cast()this).time = t;
}
I know I can make it work by casting, my question is:
we had a lock on the owning shared object already, WHY we still need the
cast to make it compile.
Because the system don't know if just this lock is enough to protect
this specific access. When you have multiple locks protecting multiple
data, things can become messy.
What I really miss is some way of telling the compiler "OK, I know what
I'm doing, I'm already in a critical section, and that all the
synchronization issues have been already managed by me".
Within this block, shared would implicitly convert to non-shared, and
the other way round, like this (in a more complex setup with a RWlock):
```
setTime(ref SysTime t) shared {
synchronized(myRWMutex.writer) critical_section { // From this point I
can forget about shared
time = t;
}
}
```
As a workaround, I have implemented the following trivial helpers:
```
mixin template unshareThis() {
alias S = typeof(this);
static if (is(S C == shared C)) {}
static if (is(S == class) || is(S == interface)) {
C unshared = cast(C) this;
} else static if (is(S == struct)) {
C* unshared = cast(C*) &this;
} else {
static assert(0, "Only classes, interfaces and structs can be
unshared");
}
}
pragma(inline, true);
ref unshare(S)(return ref S s) {
static if (is (S C == shared C)) { }
return *(cast(C*) &s);
}
```
With them you should be able to do either:
```
synchronized setTime(ref SysTime t) shared {
mixin unshareThis;
unshared.time = t;
}
```
(useful if you need multiple access), or:
```
synchronized setTime(ref SysTime t) shared {
time.unshare = t;
}
```