C# 线程安全一次性

C# 线程安全一次性,c#,idisposable,C#,Idisposable,在处理IDisposable资源时,我需要确保线程安全。该资源在内存中被缓存多次。当从缓存中逐出条目时,我们有一个回调调用Dispose() 因此,如果资源被缓存三次,我们将调用Dispose()三次 IDisposable资源负责确保线程安全还是调用者负责 IDisposable资源是负责确保线程安全还是调用者 调用方可以通过lock原语或MonitorclassIDisposable来保证线程安全,这与线程安全无关。这只是一个信号,表明对象的实例已准备好进行垃圾收集。实现IDisposabl

在处理
IDisposable
资源时,我需要确保线程安全。该资源在内存中被缓存多次。当从缓存中逐出条目时,我们有一个回调调用
Dispose()

因此,如果资源被缓存三次,我们将调用
Dispose()
三次

IDisposable
资源负责确保线程安全还是调用者负责

IDisposable资源是负责确保线程安全还是调用者


调用方可以通过
lock
原语或
Monitor
class
IDisposable
来保证线程安全,这与线程安全无关。这只是一个信号,表明对象的实例已准备好进行垃圾收集。

实现IDisposable接口的类负责确保可以多次调用该方法而不会引发异常

为了帮助确保资源始终得到适当的清理,Dispose方法应该可以多次调用,而不会引发异常

在对象被释放后,由于对象被释放而失败的调用可以并且很可能应该抛出ObjectDisposedException(以帮助将来的调试)。如果外部对象在进行调用之前知道对象是否已释放(因为该对象是共享的)很重要,则通常会添加指示对象状态的公共布尔属性(IsDisposed/disposed)


编辑:为了更清楚地回答问题的措辞,如果预期该类将在跨线程环境中使用,那么实现IDisposable的类应该实现线程安全。我发布的链接在页面底部显示了一个示例。

答案取决于您要处理的对象是否符合指南

如果他们做了一些简单的事情,从:

如果对象的Dispose方法被多次调用,则该对象必须忽略第一次调用之后的所有调用。如果多次调用该对象的Dispose方法,则该对象不得引发异常。当资源已经被释放时,Dispose以外的实例方法可以抛出ObjectDisposedException

因此,如果多次调用Dispose除了第一次调用之外没有任何效果,那么您只需确保不会同时调用它们。这绝对是打电话的人的责任


斯蒂芬·克利里(Stephen Cleary)写了一篇关于CodeProject和可能出现的问题的文章,我发现这些问题非常有帮助。

  • 正在逐出值并调用
    Dispose
    的系统必须使用同步,以确保调用不会重叠
  • 对象本身必须以可以从多个线程安全调用的方式实现
    Dispose
  • 这两种方法都是完全有效的解决方案。哪一个更好将在很大程度上取决于您的系统


    在其他条件相同的情况下,我会选择2。我更喜欢让我的对象自给自足,并且尽可能不需要帮助就可以在它们设计的环境中成功执行。使其线程安全减少了系统其他部分正确使用它所需的知识

    IDisposable
    接口不能保证线程安全。除非明确指定,否则不要假设函数是线程安全的。只有当没有代码可以再次使用对象时,才必须释放该对象。这自动意味着它是线程安全的。它可能意味着它是线程安全的,但不能保证它@SLaks我没有对线程安全做任何假设-我只是想知道谁的责任是使它线程安全。@HansPassant:对对象调用
    Dispose
    将中断使用该对象的任何操作,但这种中断有时是必要和适当的,特别是在使用阻塞I/O时(例如,如果工作线程在等待某些数据到达时被阻塞,并且用户单击“取消”,则处理连接通常是让工作线程立即进行的最干净的方式)。连接类型将需要包含代码,以确保处理是线程安全的,但这通常并不太困难。但是,当从多个线程调用时,这是不同的。如果对象执行的操作非常简单,例如设置bool以指示其已被处理,则存在一个竞争条件,其中
    Dispose
    称为twice和这两种方法都通过了
    isDisposed
    检查,然后将其设置为
    true
    。大多数
    IDisposable
    对象都没有防止这种情况发生所需的适当同步工具。@Servy是的,这就是为什么我说调用者有责任确保线程安全。@Dirk:在某些情况下,它可能不存在ot对于调用者来说是切实可行的,以确保线程安全。如果可以异步接收中止I/O流上的操作的请求(例如,从用户单击“取消”),则
    Dispose
    是线程安全的(导致任何挂起或未来的操作失败,并出现确定性异常)可能比要求调用者确保线程安全要容易得多(如果代码使用阻塞I/O,则可能需要在连接上的操作“正在进行”[阻塞];这很难使调用者中的线程安全)。