I have a class that owns a CancellationTokenSource
.
public class GrabboxCell : UICollectionViewCell
{
CancellationTokenSource _tokenSource = new CancellationTokenSource ();
// ...
}
I'm using current token to start some long-running operations.
My object also needs to support “recycling”. Think reincarnation. All long-running operations started during previous life must be cancelled.
In this case I call Cancel
and Dispose
on the source, and issue a new token source:
void CancelToken (bool createNew)
{
_tokenSource.Cancel ();
_tokenSource.Dispose ();
_tokenSource = null;
if (createNew) {
_tokenSource = new CancellationTokenSource ();
}
}
I call this method in two places: when I want the token to expire and when this class is disposed.
public override void PrepareForReuse ()
{
CancelToken (true);
base.PrepareForReuse ();
}
protected override void Dispose (bool disposing)
{
CancelToken (false);
base.Dispose (disposing);
}
Sometimes I'm getting an ObjectDisposedException
when calling _tokenSource.Cancel ()
from my Dispose
method. Documentation says:
All public and protected members of
CancellationTokenRegistration
are thread-safe and may be used concurrently from multiple threads, with the exception ofDispose
, which must only be used when all other operations on theCancellationTokenRegistration
have completed.
I'm not sure what to do at this moment. Wrap CancelToken
in a lock
?
Where exactly does the race condition happen and how to mitigate it?
I know for sure that PrepareForReuse
is always called on the same thread, but Dispose
may be called on a different one.
If this is of any use, I'm running Mono and not .NET Framework but I'm pretty sure they should have the same semantics regarding cancellation tokens.
This isn't really interesting but I wrapped Cancel
and Dispose
into a try-catch that swallows ObjectDisposedException
and haven't had problems since.