14.10.2013 17:42, robert пишет:
Damn it, you are right I did not think this through, somehow thought the
use in addrOf is enough, which is of course crap. Thank's a lot for your
time, I'll fix this ASAP.
So, here are your revised version:
https://github.com/phobos-x/phobosx/blob/1f0016c84c2043da0b9d2dafe65f54fcf6b6b8fa/source/phobosx/signal.d
Sorry, but you are making the same mistake again.
Lets start from the hardware. Just like a compiler CPU is free to do
whatever it wants with passed instructions but guarantee result state
will be the same as if it is executed sequentially. And it doesn't
assume access from other threads by default (see e.g. "out-of-order
execution"). So memory barriers (memory fences) are needed to ensure
loads/stores before the barrier are performed and no loads/stores after
the barrier are executing. This is what `core.atomic.atomicFence` does
and it can be used in e.g. in mutex implementations. As your operations
with `_obj` are already atomic no `atomicFence` call is needed.
Now let's assume without loss of generality `InvisibleAddress.address`
returns `cast(void*) ~_addr`, inline the `address` call, and remove
redundant `atomicFence` call:
```
auto tmp = atomicLoad(_obj);
auto o = cast(void*) ~tmp._addr;
if(o is null) return null;
GC.addrOf(o);
auto tmp1 = atomicLoad(_obj);
if(o is cast(void*) ~tmp1._addr)
return cast(Object) o;
assert(cast(void*) ~tmp1._addr is null);
return null;
```
As I mentioned above you are making the same incorrect assumption that
you know what machine instructions a compiler will generate. Never make
such assumptions. Here is an example of how your code can be rewritten
by a compiler:
```
auto tmp = atomicLoad(_obj);
if(tmp._addr == -1) return null;
GC.addrOf(cast(void*) ~tmp._addr);
auto tmp1 = atomicLoad(_obj);
if(tmp._addr == tmp1._addr)
return cast(Object) cast(void*) ~tmp._addr;
assert(tmp1._addr == -1);
return null;
```
--
Денис В. Шеломовский
Denis V. Shelomovskij