Comment #0 by stanislav.blinov — 2014-02-11T15:31:31Z
TDPL prohibits using operators on shared variables. I.e. this:
shared int i;
++i;
is illegal. It is stated that core.atomic should be used instead:
shared int i;
atomicOp!"+="(i, 1);
However, there are cases when this can introduce unnecessary performance loss: e.g. private shared variables that are only ever accessed under a lock.
I'm proposing to add two functions to core.atomic to allow for operations on shared variables without atomicOp()'s performance penalties:
1) localOp:
performs and acquire-op-release, e.g.:
shared int i;
auto v = localOp!"+="(i, 1);
Useful when there's still need for ordering. Though I don't really like the name "localOp".
2) assumeLocal:
converts shared lvalue to a non-shared lvalue, e.g:
shared int i;
++assumeLocal(i);
Comment #1 by andrej.mitrovich — 2014-02-11T15:36:23Z
(In reply to comment #0)
> 2) assumeLocal:
>
> converts shared lvalue to a non-shared lvalue, e.g:
>
> shared int i;
> ++assumeLocal(i);
shared int i;
++cast()i;
Comment #2 by stanislav.blinov — 2014-02-11T15:39:09Z
(In reply to comment #1)
> shared int i;
> ++cast()i;
cast()i would cast away everything, including const, silently :)
Comment #3 by andrej.mitrovich — 2014-02-11T15:49:51Z
(In reply to comment #2)
> (In reply to comment #1)
>
> > shared int i;
> > ++cast()i;
>
> cast()i would cast away everything, including const, silently :)
Oops. Maybe something like:
-----
template Unshared(T)
{
static if (is(T U == shared inout const U)) alias Unshared = U;
else static if (is(T U == shared inout U)) alias Unshared = U;
else static if (is(T U == shared const U)) alias Unshared = U;
else static if (is(T U == shared U)) alias Unshared = U;
else alias Unshared = T;
}
ref unshared(T)(ref T var)
{
return *cast(Unshared!T*)&var;
}
void main()
{
shared int x;
++unshared(x);
assert(x == 1);
}
-----
Unshared code based off of Unqual.
Comment #4 by andrej.mitrovich — 2014-02-11T15:50:29Z
(In reply to comment #3)
> template Unshared(T)
> {
> static if (is(T U == shared inout const U)) alias Unshared = U;
> else static if (is(T U == shared inout U)) alias Unshared = U;
> else static if (is(T U == shared const U)) alias Unshared = U;
> else static if (is(T U == shared U)) alias Unshared = U;
> else alias Unshared = T;
> }
Uhh that should teach me to copy-paste, the RHS should simply strip shared, not strip all the qualifiers.
Comment #5 by andrej.mitrovich — 2014-02-11T15:51:03Z
(In reply to comment #4)
> Uhh that should teach me to copy-paste, the RHS should simply strip shared, not
> strip all the qualifiers.
Fixed:
template Unshared(T)
{
static if (is(T U == shared inout const U)) alias Unshared = inout const U;
else static if (is(T U == shared inout U)) alias Unshared = inout U;
else static if (is(T U == shared const U)) alias Unshared = const U;
else static if (is(T U == shared U)) alias Unshared = U;
else alias Unshared = T;
}
Comment #6 by stanislav.blinov — 2014-02-11T15:57:16Z
Something a bit less involving :)
ref auto assumeLocal(T)(ref shared T var) @trusted pure nothrow
{
return *cast(T*)&var;
}
I should've probably noted that I already have implementations for both functions in mind, just not in the state of pull request yet.
But comments, suggestions, objections and improvements are key!
Comment #7 by stanislav.blinov — 2014-02-11T16:01:43Z