On 22.10.18 14:39, Aliak wrote:
On Monday, 22 October 2018 at 10:26:14 UTC, Timon Gehr wrote:
---
module borked;

void atomicIncrement(int* p)@system{
    import core.atomic;
    atomicOp!("+=",int,int)(*cast(shared(int)*)p,1);
}

struct Atomic(T){
    private T val;
    void opUnary(string op : "++")() shared @trusted {
        atomicIncrement(cast(T*)&val);
    }
}
void main()@safe{
    auto a=new Atomic!int;
    import std.concurrency;
    spawn((shared(Atomic!int)* a){ ++*a; }, a);
    ++a.val; // race
}
---


Oh no! The author of the @trusted function (i.e. you) did not deliver on the promise they made!

hi, if you change the private val in Atomic to be “private shared T val”, is the situation the same?

It's a bit different, because then there is no implicit unshared->shared conversion happening, and this discussion is only about that. However, without further restrictions, you can probably construct cases where a @safe function in one module escapes a private shared(T)* member to somewhere else that expects a different synchronization strategy.

Therefore, even if we agree that unshared->shared conversion cannot be implicit in @safe code, the 'shared' design is not complete, but it would be a good first step to agree that this cannot happen, such that we can then move on to harder issues.

E.g. probably it would be good to have something like @trusted data that cannot be manipulated from @safe code, such that @trusted functions can rely on some invariants.

Reply via email to