在某些C++/CLI代码中,我有一个本机类,其中有一个工厂方法GetWrapper()
用于创建它自己的受管.NET包装器对象。在内部,它通过GCHandle持有对其包装的弱引用。当调用GetWrapper()
时,将检查GCHandle,并返回现有包装器的句柄,或者(如果它不再指向对象,因为旧包装器对象已被垃圾收集器销毁),则创建一个新包装器返回。GCHandle.IsAllocated不会将弱句柄返回false以销毁对象
// .h
class NativeClass
{
public:
WrapperClass^ GetWrapper();
private:
WrapperClass^ GetNewWrapper();
GCHandle m_wrapperGCHandle;
};
// .cpp
WrapperClass^ NativeClass::GetWrapper()
{
if(m_wrapperGCHandle.IsAllocated)
{
try
{
WrapperClass^ wrapper = nullptr;
wrapper = dynamic_cast<WrapperClass^>(wrapperGCHandle.Target);
if(wrapper == nullptr)
{
return GetNewWrapper();
}
else
{
return wrapper;
}
}
catch(System::InvalidOperationException^)
{
return GetNewWrapper();
}
else
{
return GetNewWrapper();
}
}
WrapperClass^ NativeClass::GetNewWrapper()
{
WrapperClass^ wrapper = gcnew WrapperClass(/*some args*/);
m_wrapperGCHandle = GCHandle::Alloc(wrapper, GCHandleType::Weak);
}
奇怪的,现在是m_wrapperGCHandle.IsAllocated
总是返回true,即使包装已被垃圾收集。将MSDN tells设置为“在使用弱句柄时使用此属性来确定GCHandle是否仍然可用”。但它总是如此。如果它不可用,那么Target就是一个nullptr。
我错过了什么或者是MSDN错误吗?
您的代码中存在隐式线程竞争。测试IsAllocated后,GC可能会运行正常。 –
@HansPassant是的,它目前不是线程安全的 –