简体   繁体   English

多次调用CancellationTokenSource.Cancel是否安全?

[英]Is it safe to call CancellationTokenSource.Cancel multiple times?

For example, if I want to cancel some operation in a Dispose() call (which can be called multiple times ), then do I need to write 例如,如果我想取消Dispose()调用中的某些操作( 可以多次调用 ),那么我是否需要编写

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

or is it enough with the simpler 还是简单就足够了

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

(You are welcome to comment on whether it is wise or not to cancel things in a Dispose method, but that is not the point of this question.) (欢迎您评论在Dispose方法中取消操作是否明智,但这不是这个问题的重点。)

Yes. 是。

But only if the CancellationTokenSource has not been disposed yet. 但是, CancellationTokenSource是尚未CancellationTokenSource

From the reference source : 参考源

ThrowIfDisposed();

// ...

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

This seems more a question about the Dispose pattern, then about CancellationToken or anything else. 这似乎是关于Dispose模式的一个问题,然后是关于CancellationToken或其他任何问题。 And I am uncertain if you implemented said pattern properly. 我不确定您是否正确实施了上述模式。 Here is the official MS Document on the mater: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/dispose-pattern 这是母版上的官方MS文档: https : //docs.microsoft.com/zh-cn/dotnet/standard/design-guidelines/dispose-pattern

And here my interpretation: 这是我的解释:

There is two levels of Disposing: Dispose and Finalizsation. 有两个处理级别:Dispose和Finalizsation。 As the code for both is very similar, often they are combiend into one function (in C# usually it is Dispose one). 由于两者的代码非常相似,因此通常将它们组合为一个函数(在C#中通常为Dispose)。 The main difference is if you relay it to contained classes. 主要区别在于是否将其中继到包含的类。 You always relay a Dispose call(the relay is usually what Dispose is about). 您总是中继一个Dispose调用(中继通常是Dispose所涉及的)。 You never relay a Finalization call (Finalisation is between that instance and the GC only). 您永远不会中继Finalization调用(Finalization仅在该实例与GC之间)。

There are also two cases: One in wich you handle Unmanaged resources directly. 还有两种情况:一种是直接处理非托管资源。 And one in wich you handle just another Disposeable class. 其中一个仅处理另一个Disposeable类。

Unamanged resource directly 直接无损资源

In this case the first thing you do is implement a Finalizer, so at least the GC can reliably clean this up. 在这种情况下,您要做的第一件事是实现终结器,因此至少GC可以可靠地清除它。 Then you implement IDisposeable as an additional feature so programmers can use stuff like the using pattern to have it cleaned up deterministic at runtime. 然后,您将IDisposeable实现为附加功能,以便程序员可以使用诸如using模式之类的东西来在运行时清除确定性。

Handling something that implements IDisposeable 处理实现IDisposeable的东西

You have a resource that implements IDisposeable (say like a Filestream Reference). 您有一个实现IDisposeable的资源(例如文件流引用)。 You implement IDisposeable in your class for the sole purpose of relaying the Dispose() call to said FileStream. 您在类中实现IDisposeable的唯一目的是将Dispose()调用中继到所述FileStream。 This is the way more common case. 这是更常见的情况。 It would guess it makes about 95-99% of all Dispose Implementations. 大概占所有Dispose实现的95-99%。

One thing to keep in mind here is that "Dispose" and "Finalize" often implies lower level cleanup. 这里要记住的一件事是,“处置”和“完成”通常意味着较低级别的清除。 A SQLConenction you call dispose on will be closed first (if nessesary). 调用dispose的SQLConenction将首先关闭(如果需要)。 A Filehandle you Dispose off will also first be closed. 您处理掉的文件句柄也将首先关闭。 Even if calling cancellationTokenSource.Cancel was not repeatable, cancellationTokenSource.Dispose should call Cancel as part of it's operation and should be Repeatable. 即使调用cancellationTokenSource.Cancel不可重复, cancellationTokenSource.Dispose应在其操作过程中调用Cancel,并且应可重复。 The class itself does implement IDisposeable. 该类本身确实实现了IDisposeable。 And if any class does, it is usually saver to just call Dispose rather then manually doing the cleanup manually via Cancel: https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource?view=netframework-4.7.2 并且,如果有任何类,通常只调用Dispose而不是通过取消手动进行清除通常是节省的: https : //docs.microsoft.com/zh-cn/dotnet/api/system.threading.cancellationtokensource?view=网络框架4.7.2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM