d的线安弱引用实现
import core.atomic,core.memory;
private alias void delegate(Object) DEvent;
private extern (C) void rt_attachDisposeEvent(Object h, DEvent e);
private extern (C) void rt_detachDisposeEvent(Object h, DEvent e);
final class Weak(T : Object)
{
private size_t _object;
private size_t _ptr;
private hash_t _hash;
this(T object)
in
{
assert(object);
}
//用保守垃集技巧.不适用`压缩/复制`.如`D`添加`压缩`,则用`内置`弱引用.
do
{
//动 ptr=cast(size_t)cast(void*)object;
auto ptr = cast(size_t)*(cast(void**)&obj);
// 使用原子,因为并非所有架构都可保证这些值的原子存储和加载
atomicStore(*cast(shared)&_object, ptr);
// 只赋值一次,所以没有原子
_ptr = ptr;
_hash = typeid(T).getHash(&object);
rt_attachDisposeEvent(object, &unhook);
GC.setAttr(cast(void*)this, GC.BlkAttr.NO_SCAN);
}
@property T object()
{
auto obj = cast(T)cast(void*)atomicLoad(*cast(shared)&_object);
// 移动对象,至垃集堆,因而,可查询是否活着.
//注意,即使`objlocal`的强制转换和赋值
//未把对象放入栈,此调用也会.
//所以,这是安全的
if (GC.addrOf(cast(void*)obj))return obj;
return null;
}
private void unhook(Object object)
{
rt_detachDisposeEvent(object, &unhook);
//该赋值很重要.
//如果收集时,不置`mObject`为空,则`垃集`为新对象`重用`内存时,对象中的检查,可能返回`假阳`性.
atomicStore(*cast(shared)&_object, cast(size_t)0);
}
override equals_t opEquals(Object o)
{
if (this is o)return true;
if (auto weak = cast(Weak!T)o)
return _ptr == weak._ptr;
return false;
}
override int opCmp(Object o)
{
if (auto weak = cast(Weak!T)o)
return _ptr > weak._ptr;
return 1;
}
override hash_t toHash()
{
auto obj = object;
return obj ? typeid(T).getHash(&obj) : _hash;
}
override string toString()
{
auto obj = object;
return obj?obj.toString():toString();
}
}
注意:
1,为简单起见,我搞成类.不值得变成构,因为弱引用已经暗示了垃集.
2,实现依赖atomicLoad/atomicStore来,在x86上使用实际加锁前缀指令(及其他架构上的等效指令),而不是如自旋锁.
3,显然不适合压缩GC.理想情况下,压缩垃集全面支持弱(或软)引用,因此不必侵改.但是,在那之前,恕我直言,这是标准库的必要补充.
4,该类不支持存储对象上的自定义重载,opEquals()或opCmp();它总是等价的用引用.还在构建时存储哈希值.这是必要的,因为Weak(T)不能按AA键使用,因为需要调用容器对象(会被垃集)上方法时,无法维护不变量.
5,严格来说,在x86上原子不是必需的,因为一切都是size_t,并且加载/存储他们同样保证是原子的.但是,为了安全,我选择了用原子来匹配非x86架构.
5,我知道,我未用类型或方法限定符来注解.现在更专注实现.
6,黑客,黑客,黑客.我知道这并不漂亮,但除此外,无好方法来用保守的垃集线程安全方式来实现它.
auto ptr = cast(size_t)*cast(void**)&object;
对象可能有opCast方法,如上避免意外调用它.
浙公网安备 33010602011771号