c# - 强制终结器顺序

标签 c# weak-references finalizer

总体概述

我需要绑定(bind)具有 4 个主要功能的 native API:

void ActivateEngine();
int CreateModule();
void DestroyModule(int id);
void TerminateEngine();

文档指出 ActivateEngineTerminateEngine 应该包含对 CreateModuleDestroyModule 的任何调用。那就是用法应该是这样的:

void foo()
{
    ActivateEngine();

    int module1 = CreateModule();
    int module2 = CreateModule();

    ...

    DestroyModule(module2);
    DestroyModule(module1);

    TerminateEngine();
}

为此,我创建了两个 .NET 对象,即 EngineModule,它们都使用 DllImport 属性绑定(bind)到 native API。

Engine 对象充当单例并绑定(bind)到 ActivateEngineTerminateEngine

Module 对象用于在 Engine 中创建许多实例,并绑定(bind)到 CreateModuleDestroyModule 中 native API。

遇到问题

我的实现方式是用户可以直接创建Modules,而无需过多地了解Engine 或对象的生命周期(即我不[而且我不想]强制用户处理不再使用的对象)。

为此,我在 Engine 对象中使用了一个 WeakReference 列表,它指向所有已创建的 Modules

查看我的简化代码 here .

问题在于,当应用程序结束时,以非确定性方式调用终结器并且 WeakReference 目标已经为空,即使 Module 的终结器尚未被调用,而且参数 trackResurrection 设置为 true。

在我的例子中,代码记录了以下内容:

ActivateEngine() ...
CreateModule() ==> 0 ...
CreateModule() ==> 1 ...
DestroyModule(1) ...
  Ooops ... Can't dispose registered module because WeakReference to it is already null ...
  Ooops ... Can't dispose registered module because WeakReference to it is already null ...
TerminateEngine() ...
DestroyModule(0) ...

这当然是不恰当的顺序。

问题

如何强制所有 ModuleEngine 之前完成?

我真的不想强制最终用户在 Module 对象上调用 Dispose 方法,我也不想保留对创建的 的强引用>Module 以便对象在代码中不再引用时可以自动消失。示例:

 processing
 {
     var module = new Module();
     ...
 }

 foo()
 {
     processing();
     GC.Collect(); // If using strong references 'module' is gonna be kept alive (that's not smart)  
 }

我使用 ConditionalWeakTable 查看了以下线程:

但我不明白这对我的情况有何帮助。

最佳答案

更多的是针对您的特定情况的解决方法,而不是一般问题的解决方案:

将终止引擎的义务分配给引擎单例和模块对象。

创建一个您通过 Interlocked methods 更新的共享计数器(或本地等价物)。这可能是一个 static volatile int 字段或一 block 非托管内存。

int 应该计算对您的应用维护的引擎的“引用”数量。在每个构造函数中以原子方式递增计数器,并在每个终结器中递减它。将计数器减少到零的终结器也调用 TerminateEngine()(并释放共享计数器)

Engine 对象也必须算作“引用”,以防您的用户让所有 Module 对象都被垃圾收集,然后开始创建新模块。否则,发动机会提前损坏。

关于c# - 强制终结器顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20972764/

相关文章:

android - Android中的适配器应该是静态内部类还是非静态内部类

android - 用于同步的空引用(监视器输入)

c# - 通过两个参数对数组进行排序

c# - 我怎样才能使我的属性验证工作?

c# - 广播接收器监听以随机间隔触发的连接变化

c# - 是否可以 Hook GC 收集的对象?

java - 迭代 WeakHashMap

java - 替换 Java 中的 Finalize()

c# - 终结器陷入无限循环

c# - 将 C# 表数据插入 SQL Server 表