A breach of immutability due to memory implicit conversions to immutable without synchronisation, maybe??
John Colvin
john.loughran.colvin at gmail.com
Mon Nov 12 09:11:04 UTC 2018
On Sunday, 11 November 2018 at 20:47:16 UTC, Steven Schveighoffer
wrote:
> On 11/11/18 2:21 PM, John Colvin wrote:
>> Take a look at this (I think?) supposed-to-be-thread-safe code
>> according to the rules of D:
>>
>> import std.stdio;
>> import core.thread;
>> import core.atomic;
>>
>> int* foo() pure
>> {
>> auto ret = new int;
>> *ret = 3; // MODIFY
>> return ret;
>> }
>>
>> shared immutable(int)* g;
>>
>> void bar()
>> {
>> immutable(int)* d = null;
>> while (d is null)
>> d = g.atomicLoad;
>> assert(*d == 3); // READ
>> assert(*d == 3); // READ AGAIN
>> }
>>
>> void main()
>> {
>> auto t = new Thread(&bar).start();
>> immutable(int)* a = foo();
>> g.atomicStore(a);
>> t.join;
>> }
>>
>> What stops the CPU executing this such that MODIFY happens
>> between READ and READ AGAIN ?
>>
>> To aid in the thought experiment, imagine if we replace `*ret
>> = 3` with `*ret = longComputation()`? It might help your
>> reasoning about re-ordering if you consider `foo` inlined.
>
> Hm... I wouldn't expect the compiler would allow reordering
> across a return boundary. Even if the inlining occurs. Implicit
> conversion of pure return values depends on that.
>
> I don't know all the rules of reordering, but this would
> definitely cause races if it was allowed to reorder the storage
> of data in *d, and the storage of d into g.
The compiler can definitely re-order over return boundaries in
general, but perhaps there is some special logic to prevent
mistakes in these cases?
> Wait, wouldn't the atomicStore create a barrier, such that all
> the code before it must execute?
>
> -Steve
Not a full memory barrier on most (all relevant?) platforms.
More information about the Digitalmars-d
mailing list