きな粉もち.net

.NET関連仕事に携わっています。OSSのソースを読んで気がついたことを中心に呟いたりブログに投稿したりしています。最近はUiPathを使ったRPAも研究中。気軽にフォローやツッコミよろしくおねがいします! Gitはここを使っています https://github.com/kinakomotitti

Windows × スレッド × 基本的なことについてまとめてみた

この記事の目的

この記事では、
スレッドの概要についてまとめること
を目的としています。
※以下の書籍を参考に勉強した結果のアウトプットとなります。

プログラミング.NET Framework 第4版 (Microsoft Press) 単行本 – 2013/10/10
Jeffrey Richter (著), 藤原 雄介 (翻訳)

アジェンダ

  1. スレッドってなに?
  2. どんな時に使う?
  3. 使うときの注意点は?
  4. 実際の使われ方は?

本題

★スレッドってなに?

スレッドについていろいろな記事が検索できるので、それを参考にするべきですが、
一言でいうと?という観点でしっくりくるものが見当たらない。
ということで、ここではスレッドは、仮想的なCPUと定義しておこうと思います。
スレッド自体は、複数個同時に存在します。
参考までに自分の端末では、ある瞬間に存在するスレッドの数は1976でした。
f:id:kinakomotitti:20180412220850p:plain
簡単のためにCPUが1つのPCについて考えます。
1つのCPUだけあるPCにおいて、ある瞬間に実行されているスレッドは1つです。
しかし、常に1つの同じスレッドだけが実行されているわけではないです。
(1つのスレッドだけが動くのであれば、ほかのアプリが完全に沈黙していることになります。
また、その1つのスレッドが無限ループに入ったとき、PCが操作不能になってしまいます。)
実際は、実行するスレッドを細かく切り替えることで動いていきます。
「1つのCPUが実行するスレッドを細かく切り替える→実行できる処理がたくさんあるように見える。」
ということから転じて、スレッドは、仮想的なCPUとしておこうと思います。

★どんな時に使う?

わかりやすい説明があった記事を参考に乗せておきます。
technet.microsoft.com

アプリケーション開発において、マルチスレッドにするべきシナリオは大きく2つあると思います。

  • 画面が固まらないようにする。

あるGUIアプリで、ボタンを押したけど、反応がない。ただの屍のようだ・・・
と思って、ほかのボタンを押してみたらアプリが白くなった。
ということってよくあると思います。
そういう場面を何とかしたいときに、ボタン押下で実行される「重たい処理」を画面を実行しているスレッドとは別のスレッドで実行して解決するシナリオです。

  • 大量の計算処理を効率よく行う。

実際に出会ったことがないのですが、並列処理をすると計算処理を短縮することができます。
1~1000までを足し算する処理を2つのスレッドでそれぞれ500ずつ分担して実行すれば、(おそらく)1つのスレッドで実行するより半分程度の時間で処理を完了することができます。
そういうイメージのシナリオです。

★使うときの注意点は?

スレッドを使うときの注意点は、まずスレッドセーフな処理であることがあげられます。
スレッドセーフについてはまた別でまとめたいと思います。
ここでは、スレッドセーフとは
複数のスレッドが同時に動作し、データの不整合を生じさせないもの
であるということでお茶を濁したいと思いますw

次の注意点はスレッド作成にかかるコストについて意識することです。
スレッドはとても便利で、設計によっては処理時間を大幅に短縮することができたり、
GUIアプリケーションの使い勝手を向上させることができます。
しかし、それらスレッド自体を作成するコスト(オーバーヘッド)も知っておくべきです。
すべてのスレッドには、スレッドコンテキストと呼ばれるデータ構造体があります。
スレッドコンテキスト構造体は、前述の「実行されるスレッドを細かく切り替える」処理で実行中のスレッドが切り替わるとき、最後に実行された状態を保持するために利用されます。
この構造体を持つこと自体が、メモリを消費します。
また、「細かく切り替える」処理はコンテキストスイッチと呼ばれる処理です。
切り替える前に状態を保存し、次に切り替えるスレッドを探すなどの処理が実行されるため、その処理自体に時間が消費されます。
また実行コンテキスト構造体と呼ばれるものもあります。
この構造体には、セキュリティ設定、論理コンテキストデータ、ホスト設定の情報が格納されます。
これらの情報についてもメモリを消費して管理することとなります。

これらのオーバーヘッドはスレッドを使い、問題を解決するためのトレードオフになります。
払うべきところは払って、無駄に払わないようにしないといけないです。

★実際の使われ方は?

感動する例があったので一部メモしておこうと思います。
それは、Visual Studioの「ビルド」です。
いつもこの手のお話でよい題材がないなぁと悩んでいましたが、これならしっくりきました。
ビルド実行中でも、Visual StudioGUIは操作が可能ですよね!
ほかにも、コードエディタでコードを編集するときに実行される自動コンパイルもよい例だと思います。

まとめ

スレッドは仮想的なCPU。
スレッドを効果的に使うことで、処理時間の短縮や、使いやすいGUIを開発できる。
スレッドには作成に時間的・メモリ的なオーバーヘッドがかかるので、無駄遣いはダメ、絶対。