4

を所有するクラスがありCancellationTokenSourceます。

public class GrabboxCell : UICollectionViewCell
{
    CancellationTokenSource _tokenSource = new CancellationTokenSource ();

    // ...
}

現在のトークンを使用して、長時間実行される操作を開始しています。

私のオブジェクトも「リサイクル」をサポートする必要があります。生まれ変わりを考えてください。前の人生で開始されたすべての長時間実行操作はキャンセルする必要があります。

この場合、ソースに対して and を呼び出しCancelDispose新しいトークン ソースを発行します。

void CancelToken (bool createNew)
{
    _tokenSource.Cancel ();
    _tokenSource.Dispose ();
    _tokenSource = null;

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

このメソッドは、トークンを期限切れにするときと、このクラスを破棄するときの 2 つの場所で呼び出します。

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

これが役立つ場合、.NET Framework ではなく Mono を実行していますが、キャンセル トークンに関しては同じセマンティクスを持つ必要があると確信しています。

4

2 に答える 2

1

操作が (個別に) スレッドセーフであることは、一連の操作が一度に実行されることを意味するものではありません。より具体的には、PrepareForReuseas として別のスレッドで実行できるためDispose、次のことが起こります。

_tokenSource.Cancel ();
_tokenSource.Dispose ();

が 1 つのスレッドで実行されると、実行前にスレッド間でコンテキスト スイッチが発生_tokenSource = null;し、別のスレッドが_tokenSource.Cancel (). しかし、最初のスレッドがキャンセルのコードの最後のブロックに到達しなかったため、tokenSource は既に破棄されており、再生成されていません。

_tokenSource = new CancellationTokenSource ();

NullPointerException私が説明したように、コンテキストの切り替えが直前ではなく直後に発生した場合でも、時々 a が発生しても驚かないでしょう_tokenSource = null;(可能性もあります)。

この問題を解決するために、Cancelメソッドをロックして、他のメソッドが終了する前にスレッドがメソッドのどの部分も実行できないようにします。

また、 メソッドが の前に呼び出されたNullPointerException場合にのみ発生するを保護するために、 Null-Conditional Operatorを使用できます。DisposePrepareForReuse

于 2019-07-08T07:53:31.063 に答える