【问题标题】:How to make sure we have only one instance, and it is disposed in a correct way如何确保我们只有一个实例,并且以正确的方式处理它
【发布时间】:2014-02-27 13:58:14
【问题描述】:

在我正在编写的软件中,我将从外部设备(通过 USB 连接)读取一些数据。我得到的驱动程序(dll 文件)不是线程安全的,一次只能使用一个实例。我必须在 C# 中为这些驱动程序编写一个包装器。鉴于我有一个多线程应用程序,我想确保:

  1. 始终只使用一个实例(可能包装器是单例?)。
  2. 它可以被释放以释放那里的驱动程序和资源 (IDisposable?)。

Disposable Singleton 可以看出意见分歧,单例是否可以是IDisposable。也许两者都有更好的解决方案?欢迎任何帮助。
现在我有一个IDisposable 单例,如下所示:

using System;
using System.Runtime.InteropServices;

namespace Philips.Research.Myotrace.DataReading.Devices
{
    class MyDevice: IDisposable
    {
        private static volatile MyDeviceInstance;
        private static object SyncRoot = new Object();

        private bool disposed = false;

        private MyDevice()
        {
            //initialize unmanaged resources here (call LoadLibrary, Initialize, Start etc)
        }

        public MyDevice GetInstance()
        {
            if (Instance == null)
            {
                lock (SyncRoot)
                {
                    if (Instance == null)
                    {
                        Instance = new MyDevice();
                    }
                }
            }

            return Instance;
        }

        public void Dispose()
        {
            this.Dispose(true);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    //dispose of unmanaged resources here (call Stop and Close from reflection code

                    Instance = null;
                }

                this.disposed = true;
            }
        }

        [DllImport("devicedrivers.dll")]
        private static extern bool Initialize();
        [DllImport("devicedrivers.dll")]
        private static extern bool LoadLibrary();
        [DllImport("devicedrivers.dll")]
        private static extern bool Start();
        [DllImport("devicedrivers.dll")]
        private static extern bool Stop();
        [DllImport("devicedrivers.dll")]
        private static extern bool Close();
        //and few more
    }
}

【问题讨论】:

  • 您真的需要处理它吗?你什么时候这样做?大概只是在应用程序结束时 - 如果该过程即将消失,为什么还要明确发布它? (它会自动发生。)您可能还想阅读 csharpindepth.com/Articles/General/Singleton.aspx 以使您的单例模式更简单。
  • 如果我不调用适当的关闭函数(没有来自驱动程序源的文档),我不确定非托管代码(驱动程序)的行为方式
  • 操作系统通常负责在进程终止时清理非托管资源。对于您希望在整个过程中保持开放的资源,这应该没问题。
  • 那太好了,如果您将所有这些都作为答案,我可以将其标记为正确答案。再次感谢您的时间:)
  • @DanielGruszczyk,您可以使用 this 之类的东西来为非线程安全的非托管 DLL 实现线程亲和性。

标签: c# multithreading design-patterns idisposable


【解决方案1】:

操作系统负责在进程终止时清理非托管资源。所以如果你很高兴从你第一次使用资源到程序终止的那一点分配资源,我根本不会实现IDisposable

话虽如此,为了可测试性,我很可能会避免公开暴露单例。考虑创建一个接口并使用依赖注入在整个代码中注入相同的实例。我通常不喜欢单身人士。但是,如果您要使用其中一种,我建议您遵循我的article on singletons 中的一种后期模式。避免所有这些双重检查锁定废话:)

【讨论】:

  • 我忘了说你关于单身人士的文章很棒,而且这本书看起来也很有趣。感谢您的意见。
【解决方案2】:

我不建议使用直接一次性的静态单例,而是使用一种方法来返回封装当前连接的设备的IDisposable 对象(或对象列表)。许多主要限于单线程操作的 USB 驱动程序都有一个允许多线程的情况:任何线程都可能请求关闭驱动程序实例,从而导致任何未决或未来的操作在第一时间中止。关闭可能不是立即的,如果想要关闭并重新启动已“卡住”的设备,则必须准备好在关闭完成之前重新打开尝试可能会失败和/或阻塞的可能性。

虽然操作系统会在程序退出时尝试清理程序可能正在使用的任何 USB 设备驱动程序,但这种清理并不总是有效,我会避免依赖它。当您知道不再需要它们时,最好将它们处理掉。从抽象的角度来看,如果使用单例方法来识别连接的设备(如果有的话),那么处理由此识别的设备就没有问题。设备处理完毕后,它们将不再出现在列表中,直到重新建立连接为止。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多