如何确保只有一个实例,并以正确的方式处理其释放(在IT技术方面)

7
在我编写的软件中,将从外部设备(通过USB连接)中读取一些数据。 我得到了给定的驱动程序(dll文件),它们不是线程安全的,一次只能使用一个实例。 我必须用C#编写一个包装器来封装这些驱动程序。 鉴于我有一个多线程应用程序,我希望确保:
  1. 始终只使用一个实例(可能是单例模式的包装器?)。
  2. 可以销毁以释放那里的驱动程序和资源(IDisposable?)。
可处理的单例模式中,我可以看到意见分歧,单例模式是否可以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
    }
}

6
你真的需要处理它吗?何时才需要处理?可能只有在应用程序结束时才需要处理,如果进程正在消失,为什么要明确释放它呢?(这将自动发生。)你可能还想阅读http://csharpindepth.com/Articles/General/Singleton.aspx,以使您的单例模式更简单。 - Jon Skeet
我不确定未托管的代码(驱动程序)将如何行为,如果我没有调用适当的关闭函数(来自驱动程序源的文档)。 - Daniel Gruszczyk
1
操作系统通常负责在进程终止时清理非托管资源。对于您想要在整个进程期间保持打开状态的资源,这应该是可以的。 - Jon Skeet
好的,如果你把所有的东西都作为答案给出来,我就可以把它标记为正确的。再次感谢你的时间:) - Daniel Gruszczyk
@DanielGruszczyk,你可以使用类似这个的方法来为非线程安全的非托管DLL实现线程亲和性。 - noseratio - open to work
2个回答

3
操作系统在进程终止时负责清理非托管资源。因此,如果您希望资源从第一次使用资源开始分配直到程序终止,我将不会实现IDisposable。
话虽如此,为了进行测试,我可能会避免公开单例。考虑创建一个接口,并使用依赖注入在整个代码中注入相同的实例。我通常不喜欢单例。如果您要使用其中之一,请遵循我关于单例的文章中的后面的模式。避免所有这些双重检查锁定的荒谬 :)

我忘了说你关于单例模式的文章很棒,这本书看起来也很有趣。感谢你的贡献。 - Daniel Gruszczyk

0

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

虽然操作系统将尝试在退出时清理程序可能正在使用的任何USB设备驱动程序,但这种清理并不总是有效的,因此我建议避免依赖它。最好在不再需要时处理掉你能够处理的东西。从抽象的角度来看,如果使用一个单例方法来识别已连接的设备(如果有的话),则处理掉由此标识的设备没有问题。一旦设备被处理掉,它们将不再出现在列表中,直到采取某些措施重新建立连接。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接