首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >CancellationTokenSource.Cancel抛出一个ObjectDisposedException

CancellationTokenSource.Cancel抛出一个ObjectDisposedException
EN

Stack Overflow用户
提问于 2013-02-02 10:58:17
回答 2查看 6.1K关注 0票数 4

我有一个拥有CancellationTokenSource的类。

代码语言:javascript
复制
public class GrabboxCell : UICollectionViewCell
{
    CancellationTokenSource _tokenSource = new CancellationTokenSource ();

    // ...
}

我正在使用当前令牌启动一些长期运行的操作。

我的目标也需要支持“回收”。想想转世吧。在前世开始的所有长期运行的操作都必须取消。

在本例中,我在源上调用CancelDispose,并发出一个新的令牌源:

代码语言:javascript
复制
void CancelToken (bool createNew)
{
    _tokenSource.Cancel ();
    _tokenSource.Dispose ();
    _tokenSource = null;

    if (createNew) {
        _tokenSource = new CancellationTokenSource ();
    }
}

我在两个地方调用这个方法:当我希望令牌过期时和这个类被释放时。

代码语言:javascript
复制
public override void PrepareForReuse ()
{
    CancelToken (true);
    base.PrepareForReuse ();
}

protected override void Dispose (bool disposing)
{
    CancelToken (false);
    base.Dispose (disposing);
}

有时,当从我的ObjectDisposedException方法调用_tokenSource.Cancel ()时,我会得到一个Dispose。文件上说:

CancellationTokenRegistration的所有公共成员和受保护成员都是线程安全的,可以从多个线程并发使用,但Dispose除外,只有在CancellationTokenRegistration上的所有其他操作完成后才能使用。

我现在不知道该怎么办。将CancelToken包装在lock

比赛条件究竟是在哪里发生的,如何加以缓解?

我确信,PrepareForReuse总是在同一个线程上被调用,但是Dispose可能在另一个线程上被调用。

如果这是有用的,我运行的是Mono,而不是.NET框架,但我非常肯定,它们在取消令牌方面应该具有相同的语义。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-02-08 19:55:52

这并不是很有趣,但我把CancelDispose包装成了一个尝试捕获,燕子ObjectDisposedException,从那以后就没有问题了。

票数 7
EN

Stack Overflow用户

发布于 2019-07-08 07:53:31

线程安全的操作(单独的)并不意味着您的操作序列是立即执行的。更具体地说,由于PrepareForReuse可以以Dispose的形式在不同的线程中运行,所以可能发生的情况是:

代码语言:javascript
复制
_tokenSource.Cancel ();
_tokenSource.Dispose ();

在一个线程中执行,然后在执行_tokenSource = null;之前在线程之间切换一个上下文,然后另一个线程尝试再次运行_tokenSource.Cancel ()。但是tokenSource已经被释放,没有重新生成,因为第一个线程没有到达cancel的最后一个代码块:

代码语言:javascript
复制
_tokenSource = new CancellationTokenSource ();

如果您不时地得到一个NullPointerException,如果上下文切换发生在_tokenSource = null;之后,而不是像我解释的那样(这也是可能的),我也不会感到惊讶。

为了解决这个问题,我将锁定您的Cancel方法,以便线程在另一个方法完成之前不能运行该方法的任何部分。

此外,要保护NullPointerException,只有在调用PrepareForReuse之前调用方法Dispose时才能进行保护,您可以使用https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14661147

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档