Безопасно ли вызывать CancellationTokenSource.Cancel несколько раз? - PullRequest
0 голосов
/ 16 октября 2018

Например, если я хочу отменить какую-либо операцию в вызове Dispose() (который можно вызвать несколько раз ), тогда мне нужно написать

public void Dispose()
{
    if (!cancellationTokenSource.IsCancellationRequested)
    {
        cancellationTokenSource.Cancel();
    }
}

илидостаточно ли этого с более простым

public void Dispose()
{
    cancellationTokenSource.Cancel();
}

(Вы можете прокомментировать, целесообразно или нет отменять вещи в методе Dispose, но это не главное в этом вопросе.)

Ответы [ 2 ]

0 голосов
/ 16 октября 2018

Это, кажется, больше вопрос о шаблоне Dispose, чем о CancellationToken или чем-то еще.И я не уверен, правильно ли вы применили указанный шаблон.Вот официальный документ MS по математике: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/dispose-pattern

А вот мое толкование:

Существует два уровня утилизации: Dispose и Finalizsation.Поскольку код для обоих очень похож, часто они объединяются в одну функцию (в C # обычно это Dispose).Основное различие заключается в том, что если вы передаете его в классы.Вы всегда ретранслируете вызов Dispose (обычно речь идет о ретрансляции).Вы никогда не передаете вызов Финализации (Финализация только между этим экземпляром и GC).

Есть также два случая: один, в котором вы обрабатываете неуправляемые ресурсы напрямую.И один, в котором вы обрабатываете только другой класс Disposeable.

Непосредственный ресурс напрямую

В этом случае первое, что вы делаете, это реализует Finalizer, так что, по крайней мере, GCможет надежно очистить это.Затем вы реализуете IDisposeable в качестве дополнительной функции, чтобы программисты могли использовать такие вещи, как шаблон использования, чтобы очистить его от детерминированных во время выполнения.

Обработка чего-то, что реализует IDisposeable

Youиметь ресурс, который реализует IDisposeable (скажем, как ссылка на файловый поток).Вы реализуете IDisposeable в своем классе с единственной целью - передать вызов Dispose () указанному FileStream.Это более распространенный случай.Можно предположить, что он составляет около 95-99% от всех реализаций Dispose.

Здесь следует иметь в виду, что «Dispose» и «Finalize» часто подразумевают очистку более низкого уровня.SQLConenction, по которому вы вызываете dispose, будет закрыт первым (если он необходим).Файловый дескриптор, который вы утилизируете, также сначала будет закрыт.Даже если вызов cancellationTokenSource.Cancel не повторяется, cancellationTokenSource.Dispose должен вызвать Cancel как часть его операции и должен быть повторяемым.Сам класс реализует IDisposeable.И если это делает какой-либо класс, обычно безопаснее просто вызвать Dispose, а не вручную выполнять очистку вручную с помощью Cancel: https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource?view=netframework-4.7.2

0 голосов
/ 16 октября 2018

Да.

Но только если CancellationTokenSource еще не был утилизирован.

Из справочного источника :

ThrowIfDisposed();

// ...

// fast-path test to check if Notify has been called previously
if (IsCancellationRequested)
    return;
...