Как узнать, что объект утилизирован?

У меня многопоточное приложение, и CancellationToken используется как общий объект. Каждый поток может запустить его, чтобы сообщить другим потокам, что задание отменено. Затем один поток выполняет очистку и удаляет каждый объект, подобный этому CancellationToken. Затем, если поток пытается его использовать, возникает исключение:

CancellationTokenSource удален.

Как я могу узнать, что объект удален перед его использованием?


person Xaqron    schedule 13.04.2011    source источник
comment
Почему один поток, очищающий ресурсы, все еще используется? Мне это кажется большим недостатком дизайна.   -  person Lasse V. Karlsen    schedule 14.04.2011
comment
CancellationToken используется для синхронизации. Бывает, что два потока одновременно пытаются отменить задание. Может замок над ним поможет?   -  person Xaqron    schedule 14.04.2011
comment
Кстати, исправьте свой вопрос, вы не избавляетесь от CancellationToken, это невозможно. Вы избавляетесь от CancellationTokenSource.   -  person Lasse V. Karlsen    schedule 14.04.2011
comment
Как насчет ManualResetEvent? (Хотя я согласен с @lassee, похоже, реализация неверна.   -  person Brad Christie    schedule 14.04.2011


Ответы (4)


Что ж, согласно Reflector, CancellationTokenSource имеет внутренний метод IsDisposed, который мог бы сообщить вам, но поскольку он внутренний, вы не должны его вызывать.

В любом случае, если один поток извлекает структуры данных и объекты, от которых зависят другие потоки, не делайте этого. Исправьте свой код и оставьте эти объекты живыми до тех пор, пока они в них нуждаются.

Другими словами, подождите, пока эти другие потоки перестанут нуждаться в CancellationTokenSource, прежде чем избавляться от него.

person Lasse V. Karlsen    schedule 13.04.2011

Надлежащий курс действий для создателей некоторых одноразовых объектов будет заключаться в том, чтобы немного пойти против «правила» Microsoft, согласно которому выполнение любого действия над удаленным объектом должно вызывать исключение, и вместо этого следовать более общему правилу, согласно которому исключение должно создаваться в любое время. постусловия метода не могут быть выполнены. Если цель метода Cancel состоит в том, чтобы гарантировать, что никто не будет продолжать считать задание активным, и даже до вызова метода Cancel все считают задание мертвым, то постусловие для метода выполняется независимо от удален ли объект.

Как правило, код вне хорошо спроектированного объекта не должен запрашивать, был ли он удален, за исключением, возможно, подтверждения того, что он был удален. Вместо этого сам объект должен предоставлять методы, значение которых для удаленного объекта было бы ясным и недвусмысленным. Эти методы могут внутренне использовать флаг IsDisposed, но должны будут использовать любую блокировку, необходимую для предотвращения условий гонки. В общем, узор

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

указывает на то, что myThing действительно должен поддерживать метод DoSomethingIfNotDisposed (возможно, называемый TryDoSomething). Если вы не можете этого сделать, я мог бы написать свой собственный метод расширения DoSomethingIfNotDisposed и использовать Try/Catch для подавления ObjectDisposedException (или любого другого исключения, которое будет вызывать объект).

person supercat    schedule 14.04.2011
comment
У меня есть один, но проблема в состоянии гонки. Возможно, дескриптор ожидания решит проблему. - person Xaqron; 15.04.2011
comment
@Xaqron: если бы класс был правильно разработан, его метод Cancel просто ничего не делал бы, если он уже был удален (если он не всегда может избежать выполнения чего-то, что может вызвать исключение, он должен задушить исключение внутри себя). - person supercat; 15.04.2011

проверьте, удален ли объект, прежде чем использовать его.

Все еще не лучший шаблон дизайна. однако вот то, что я использую, определяет, удален ли объект.

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

or

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

если это не сработает, вы можете попробовать добавить флаг IsDisposed и переопределить метод dispose. И установите для этого значение true в своем собственном коде.

person The Lazy Coder    schedule 13.04.2011

Наследуйте свой класс и добавьте свойство:

class MyCancellationTokenSource: CancellationTokenSource
{
    public bool MyIsDisposed { get; private set; }
    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        MyIsDisposed = true;
     }
}
person Alex    schedule 02.11.2017
comment
CancellationTokenSource нельзя наследовать. Это закрытый класс - person Vladyslav Tsvek; 07.05.2019