2011-04-13 61 views
6

我有一个多线程应用程序和一个CancellationToken被用作共享对象。每个线程都可以触发它告诉其他线程工作被取消。然后一个线程进行清理并处理每个对象,如CancellationToken。然后,如果某个线程尝试使用它,则会引发异常:如何找出一个对象已经处理?

CancellationTokenSource已被丢弃。

如何在使用它之前找出一个对象被丢弃?

+2

为什么一个线程仍在使用的清理资源?这对我来说似乎是一个很大的设计缺陷。 – 2011-04-13 20:41:44

+0

'CancellationToken'用于同步。这发生在两个线程同时尝试取消作业时发生。也许锁定它有助于? – Xaqron 2011-04-13 20:43:40

+0

请解决你的问题btw,你不处理'CancellationToken',这是不能做到的。您正在使用'CancellationTokenSource'。 – 2011-04-13 20:45:17

回答

4

那么,根据反射器,CancellationTokenSource有一个内部的IsDisposed方法,可以告诉你,但由于它是内部的,你不应该叫它。在任何情况下,如果一个线程抽出了其他线程依赖的数据结构和对象,则不要这样做。修复你的代码,并让这些对象在需要的时候保持活动状态。

换句话说,等待这些其他线程完成需要CancellationTokenSource,然后再处理它。

1

检查对象是否在使用之前进行处理。

仍然不是最好的设计模式。然而,这里是我用来确定一个对象是否被处置。

if (!object.IsDisposed) object.DoSomething(); 

public string DoSomething() 
{ 
    if (this.IsDisposed) return null; 
} 

如果不工作,你可以尝试添加IsDisposed标志并重写Dispose方法。并在您自己的代码中将其设置为true。

2

适当的行动方案应该是让一些Disposable对象的创建者稍微违反Microsoft的“规则”,即对处置对象执行任何操作时应抛出异常,而应遵循更一般的规则,即异常应该任何时候都会抛出一个方法的后置条件无法满足。如果取消方法的目的是确保没有人会继续将工作视为存活,甚至在取消方法被调用之前,每个人都认为工作已经死亡,那么无论物体是否被丢弃。

通常,设计良好的对象之外的代码不需要查询它是否已被处置,除非可能断言它已被处置。相反,对象本身应该提供方法,其对处置对象的含义将是清晰明确的。这些方法可能在内部使用IsDisposed标志,但必须使用任何锁定来防止竞争条件。通常,图案

 
    if (!myThing.isDisposed) 
    myThing.DoSomething(); 

是myThing应该真正支持DoSomethingIfNotDisposed方法(可能称为TryDoSomething)的指示。如果你不能这样做,我的倾向可能是编写自己的DoSomethingIfNotDisposed扩展方法,并使用Try/Catch来扼杀ObjectDisposedException(或对象将抛出的任何特定异常)。

+0

我有一个,但问题是竞争条件也许等待句柄解决问题 – Xaqron 2011-04-15 02:38:14

+0

@Xaqron:。如果类被设计得当,它的取消方法将如果它已经被处置,就不做任何事情(如果它不能总是避免做一些可能导致异常的事情,它应该扼杀它自身的异常)。 – supercat 2011-04-15 12:08:39

0

继承你的类并添加属性:

class MyCancellationTokenSource: CancellationTokenSource 
{ 
    public bool MyIsDisposed { get; private set; } 
    protected override void Dispose(bool disposing) 
    { 
     base.Dispose(disposing); 
     MyIsDisposed = true; 
    } 
} 
相关问题