c# - 保证 Dispose 被称为 "when the process is ending"

标签 c# .net multithreading dispose shutdown

有一个可能共享的资源 X 与前台线程相关联,由两个实例(Y、Z)使用并作为依赖项提供。因为 X 可能会被共享,所以它不能被任何一个使用站点(Y 或 Z)丢弃。

明显的解决方案是确保 X 在不再使用后“在某个适当的时间”被手动处置:在这种情况下,可以假设这意味着 X 不再是强-可达。但是,在这种情况下,有一个 [有问题的] 客户端不会这样做。

因为 X 有一个关联的前台线程,这可以防止进程终止(完全?)。

有没有办法让 X 在没有外部依赖性的情况下,甚至不知道它是否在“可执行文件”或“Windows 服务”中 - 确保在进程终止之前/终止时调用 Dispose?

是否有更智能的方法来处理这种可能有一个或多个消费者的(未跟踪的)共享资源?

目前这依赖于终结器,但正如所宣传的那样,这是..不可靠的。

最佳答案

这不会在 X 上调用处置,但它会告诉您所有 X 何时已被 GC 收集(并每 5 分钟强制执行一次 GC)

public sealed class CollectionWatcher<T>
{
    private readonly Func<T> _objectFactory;
    private readonly List<WeakReference> _references;
    private readonly System.Timers.Timer _timer;
    private readonly Object _lockObject = new Object();

    public CollectionWatcher(Func<T> objectFactory, double minutesBetweenChecks = 5)
    {
        _objectFactory = objectFactory;
        _references = new List<WeakReference>();
        _timer = new System.Timers.Timer();
        _timer.Interval = TimeSpan.FromMinutes(minutesBetweenChecks).TotalMilliseconds;
        _timer.AutoReset = true;
        _timer.Elapsed += TimerElapsed;
    }

    public T GetObjectBecauseICantBeTrustedToDisposeCorrectly()
    {
        var result = _objectFactory();
        var wr = new WeakReference(result);
        lock (_lockObject)
        {
            _references.Add(wr);
            _timer.Start();
        }

        return result;
    }

    public event EventHandler AllItemsCollected;

    private void OnAllItemsCollected()
    {
        AllItemsCollected?.Invoke(this, EventArgs.Empty);
    }


    private void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        bool allItemCollected = false;

        GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, false);
        lock (_lockObject)
        {
            foreach (var reference in _references.Where(x => !x.IsAlive).ToList())
            {
                _references.Remove(reference);
            }

            if (_references.Count == 0)
            {
                _timer.Stop();
                allItemCollected = true;
            }
        }

        if (allItemCollected)
        {
            OnAllItemsCollected();
        }
    }
}

您不能只在 T 上调用 Dispose(),因为当 .IsAlive 为 false 时,终结器已经被调用T

我会继续思考这个问题,也许还有其他解决方案。

关于c# - 保证 Dispose 被称为 "when the process is ending",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35331952/

相关文章:

c# - 使用 C# 在同一进程中使用 IPC 管道

c# - 这是对 DTO 的正确使用吗?

java - Java线程使用join()时如何引发InterruptedExpection?

c - 双核 ARMv7 处理器中的并行处理

c# - MySQL View 在一台机器上,MySQL 表在另一台机器上。询问

c# 从 messagebox.show popup 中选择文本

c# - 处理 Excel 中的 "No cells were found."错误

c# - 异常与返回码 : do we lose something (while gaining something else)?

c# - 在 asp.net 网站中禁用 *.java 文件编译

c# - 线程引发事件被处理程序阻止?