valid uses of shared

Dmitry Olshansky dmitry.olsh at gmail.com
Mon Jun 11 10:42:37 PDT 2012


>> Are these operations on shared data all safe? Note that if these
>> accesses would be protected by some lock, then the 'shared' qualifier
>> wouldn't really be needed - compiler barriers, that make sure it all
>> happens while this thread holds the lock, would be enough. (even the
>> order of operations doesn't usually matter in that case and enforcing
>> one would in fact add overhead)
>
> No, they should not be all safe, I never suggested that. It's impossible
> to engineer a one-size-fits-all for accessing shared variables, because
> it doesn't know what mechanism you are going to use to protect it. As
> you say, once this data is protected by a lock, memory barriers aren't
> needed. But requiring a lock is too heavy handed for all cases. This is
> a good point to make about the current memory-barrier attempts, they
> just aren't comprehensive enough, nor do they guarantee pretty much
> anything except simple loads and stores.
>
> Perhaps the correct way to implement shared semantics is to not allow
> access *whatsoever* (except taking the address of a shared piece of
> data), unless you:
>
> a) lock the block that contains it
> b) use some library feature that uses casting-away of shared to
> accomplish the correct thing. For example, atomicOp.
>
It may be a good idea. Though I half-expect reads and writes to be 
atomic. Yet things like this are funky trap:
shread int x; //global
...
x = x + func();
//Booom! read-modify-write and not atomic, should have used x+= func()

So a-b set of rules could be more reasonable then it seems.

> None of this can prevent deadlocks, but it does create a way to prevent
> deadlocks.
>
> If this was the case, stack data would be able to be marked shared, and
> you'd have to use option b (it would not be in a block). Perhaps for
> simple data types, when memory barriers truly are enough, and a
> shared(int) is on the stack (and not part of a container), straight
> loads and stores would be allowed.
>
> Now, would you agree that:
>
> auto v1 = synchronized p.i;
>
> might be a valid mechanism? In other words, assuming p is lockable,
> synchronized p.i locks p, then reads i, then unlocks p, and the result
> type is unshared?
>
> Also, inside synchronized(p), p becomes tail-shared, meaning all data
> contained in p is unshared, all data referred to by p remains shared.
>
> In this case, we'd need a new type constructor (e.g. locked) to
> formalize the type.
>
> Make sense?
>

While I've missed a good portion of this thread I think we should 
explore this direction. Shared has to be connected with locks/synchronized.

-- 
Dmitry Olshansky


More information about the Digitalmars-d mailing list