2011-04-13 23 views
6

Tengo una aplicación multiproceso y CancellationToken se utiliza como objeto compartido. Cada hilo puede activarlo para decirle a los otros hilos que el trabajo está cancelado. Luego, un hilo realiza la limpieza y dispone cada objeto como este CancellationToken. Entonces, si un subproceso intenta usarlo, se genera una excepción:¿Cómo saber qué objeto ha sido eliminado?

CancelTokenSource ha sido descartado.

¿Cómo puedo saber si un objeto está dispuesto antes de usarlo?

+2

¿Por qué es la limpieza de un hilo recursos todavía en uso?Eso me parece un gran defecto de diseño. –

+0

El 'CancellationToken' se utiliza para la sincronización. Sucede cuando dos hilos intentan cancelar el trabajo al mismo tiempo. Tal vez una cerradura ayuda? – Xaqron

+0

Por favor, corrija su pregunta por cierto, no se está deshaciendo de 'CancellationToken', eso no se puede hacer. Estás rechazando el 'CancellationTokenSource'. –

Respuesta

4

Bueno, de acuerdo con Reflector, CancellationTokenSource tiene un método interno IsDisposed que podría haberte dicho, pero dado que es interno, no debes llamarlo.

En cualquier caso, si un hilo extrae estructuras de datos y objetos de los que dependen otros hilos, entonces no haga eso. Arregle su código y deje esos objetos en vivo mientras dure su necesidad.

En otras palabras, espere a que esos otros hilos terminen de necesitar el CancellationTokenSource antes de deshacerse de él.

1

compruebe si el objeto está dispuesto antes de usarlo.

Todavía no es el mejor patrón de diseño. sin embargo, aquí está lo que uso para determinar si un objeto está dispuesto.

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

o

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

si eso no funciona, puede intentar añadir una bandera IsDisposed y reemplazando el método dispose. Y estableciendo eso como verdadero en tu propio código.

2

El curso de acción adecuado sería que los creadores de algunos objetos desechables se opongan ligeramente a la "regla" de Microsoft de realizar cualquier acción sobre un objeto dispuesto y lanzar una excepción, y en su lugar seguir la regla general de que una excepción se lanzará cada vez que no se puedan cumplir las condiciones posteriores de un método. Si el propósito del método Cancelar es garantizar que nadie continúe considerando que un trabajo es en vivo, e incluso antes de que se llame al método Cancelar, todos consideran que el trabajo está muerto, entonces se cumple la condición posterior del método, independientemente de si el objeto está dispuesto.

En general, el código fuera de un objeto bien diseñado no debería necesitar consultar si ha sido eliminado, excepto posiblemente para afirmar que lo ha sido. En cambio, el objeto en sí debería proporcionar métodos cuyo significado en un objeto dispuesto sería claro y no ambiguo. Esos métodos podrían usar internamente una bandera IsDisposed, pero tendrían que usar cualquier bloqueo que fuera necesario para evitar condiciones de carrera. En general, el patrón

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

es una indicación de que MYTHing realmente debería apoyar un método DoSomethingIfNotDisposed (posiblemente llamado TryDoSomething). Si no puede hacer eso, mi inclinación podría ser escribir su propio método de extensión DoSomethingIfNotDisposed y usar Try/Catch para sofocar una excepción ObjectDisposedException (o cualquier excepción particular que arroje el objeto).

+0

Tengo una, pero el problema es la condición de carrera. Tal vez un identificador de espera resuelva el problema. – Xaqron

+0

@Xaqron: Si la clase se diseñó correctamente, su método Cancelar sería simplemente no haga nada si ya ha sido eliminado (si no siempre puede evitar hacer algo que pueda causar una excepción, debe sofocar la excepción en sí misma). – supercat

0

Heredar su clase y añadir la propiedad:

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