Rustで別スレッドの進捗状況によって処理を分岐させる

Rustで別のスレッドのある処理が完了しているかどうかで、処理を分岐させるパターンについて書きました。別のスレッドの処理の完了を必ず待たなければならない場合はfork joinやchannelなどを使うとよいでしょうが、処理が完了していない場合もすぐになんらかの処理を行いたいケースを想定しています。
また、この記事の実装は以下のバージョンのRustで動作確認しています。

$ rustc --version
rustc 1.36.0-nightly (73a3a90d2 2019-05-17)

予備知識としてRustのArc 型とWeak型について知っておく必要があるので、少し触れておきます。

Arc

Weak

Arc型もWeak型も内部的にstrongとweakという値を持っています。strongは上に書いた参照カウンタのことを指しており、参照される箇所の数が増えればカウントアップします。スコープから抜けるなど、参照される箇所の数が減るとカウントダウンします。weakは参照される箇所の数が増えてもカウントアップされることはありません。明示的にWeakポインタを作成したときにカウントアップされます。カウントダウンについてはstrongと同様です。リソースはweakとは無関係で、strongが0になると開放されます。

実装例

spawnで生成したスレッドの処理が完了していれば「準備完了」、完了していなければ「まだ」とメインスレッドで表示します。※ 2
では、処理を順に説明していきます。

Readiness はある処理が終わったかを気にするスレッド(今回の例だとメインスレッド)、 LatchReadinessが気にする処理を行うスレッド(今回の例だとspawnで生成したスレッド)で使用します。Weak型とArc 型に関しては上述したとおりです。

newArc を生成し、 Weak に変換してReadiness に渡しています。 is_ready はリソースが解放済みかを確認しています。 Latchrelease が実行されると、リソースが開放されます。

releaseReadiness::new() の際に作成した空のArc を破棄しています。

do_something0〜1000のなかのランダムな値ミリ秒間sleepする処理です。※ 3 そのため、上のプログラムを実行するたびに、releaseis_ready のタイミングが変わり、表示内容に影響を与えています。

まとめ

※ 1 https://github.com/linkerd/linkerd2-proxy/blob/master/src/app/admin/readiness.rs

※ 2 do_something()が完了していても、 l.release()が完了していなければ、「まだ」と表示されます。また、メインスレッドの処理が先に完了すると、spawnで生成したスレッドの処理は途中でも終了します。

※ 3 do_somethingの処理自体は本題から逸れるものです。

Software engineer