2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

小ネタ: CancellationTokenはどうやって作られるか?

Last updated at Posted at 2024-07-31

主に備忘録的な小ネタシリーズ。

疑問

CancellationTokenってアチコチで使う。
大体がCancellationTokenSource.Tokenで作るんだけど、プロパティだから何回参照しても同じ?

回答

CancellationTokenSource.Tokenって見た目はプロパティなんだけど、ソースを見てみたらこんな感じだった。

CancellationTokenSource.cs より
    public CancellationToken Token
    {
        get
        {
            ThrowIfDisposed();
            return new CancellationToken(this);
        }
    }

おい、毎回Newしとるやんけ!!!

でも、

hoge
    CancellationTokenSource tokenSource = new CancellationTokenSource();

    CancellationToken token1 = tokenSource.Token;
    CancellationToken token2 = tokenSource.Token;

    Assert.Equal(token1, token2);

なんてテストを書くとAssertは通る。つまりtoken1 == token2trueになる。

これは単純にCancellationTokenIEquatable<CancellationToken>を継承しているから。
で、何をもって同じと判断しているかというと、元になるCancellationTokenSourceが同じ(Equal())であれば「同じ」と見なされている。

蛇足で、GetHashCode()もしっかりOverrideされていて、元になるCancellationTokenSource.GetHashCode()を引っ張ってくるようになっている。

ついでに、CancellationTokenってstructなのね。知らんかった。
ってことはメソッドの引数にしたりするとstructは値型(Value Type)なのでコピー渡しされるってことかね??

Assert.Same()CancellationToken同士の参照を比較しようとしても、「Assert.Same()にValue Typeを入れないでね。」とレコメンドが出る。ま、そうだよね。

もしかするとCLR Runtime側で何か特別扱いしているのかもしれないけど、メソッドの引数にセットしたりするとコピー渡しされるんだろうなー。パフォーマンス原理主義者は怒るんだろうな~。
とか、考えてみる。

Register()は??

ってことは、だ、
メソッドの引数にCancellationToken渡して渡し元と渡し先で
token.Register(() => { ほげほげ}
とかやるとどうなるんだろう??

ちなみにCancellationToken.Register()は、そのToken(正確にはTokenSource)でキャンセルを行った後に実行したいActionを登録しておくことができるメソッドです。

……ってことで調べてみました。ソースを。

  • Register()は戻り値としてCancellationTokenRegistrationというClassのオブジェクトを返す。
  • Register()の中で、作ったCancellationTokenRegistrationを、Tokenの元のTokenSourceに登録している。(大雑把に言えば、CancellationTokenSource.Register()へのショートカットですね。どっちにRegister()しても結局同じ。)
  • CancellationTokenRegistrationCancellationTokenSourceCancellationTokenから.Unregister()すると、キャンセルされたときにそのCallbackは 実行されなくなる
  • もうひとつ、CancellationTokenRegistration自体をDispose()するとUnregister()されたのと同じ効果がある。
  • キャンセル時のCallbackはCancellationTokenSourceから実行される。
  • キャンセル済みのCancellationTokenSourceCancellationToken.Register()すると、Callbackは即時実行される。

なるほどね。

2
3
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?