質問 |
||
| QNo.4027960 | マルチスレッド | |
|---|---|---|
| 質問者:supertrap |
ウインドウズプログラミングを始めて1ヶ月弱の初心者です。 色々探してみたのですが、結局良く分かりませんでした。 宜しくお願いします。 以下のリンクにおいて、 http://wisdom.sakura.ne.jp/system/winapi/win32/win143.html 1)主スレッドとは、具体的にソースファイルのどこからどこまでのことを言うのでしょうか? そもそもスレッドとは何でしょうか?関数のことでしょうか? また、タスクとは、実行ファイルと考えて良いのでしょうか? 2)副スレッド(ThreadFunc)を作成すると、主スレッド(WinMain?)と副スレッドで並列処理をするとのことですが、CPUは普通一つしかないので、実際は、主スレッド(WinMain?)と副スレッドを常に切り替えながら動作すると思います。が、ここで疑問なのですが、主スレッドと副スレッドの切り替えはいつ誰が行うのでしょうか?また、切り替えタイミング(例えば1ms毎に切り替えたいとか)は自由に設定出来るのでしょうか? 3)"マルチスレッドは親プロセスのメモリ空間を共有します" とあるのですが、これは CreateThread(NULL , 0 , ThreadFunc , (LPVOID)hWnd , 0 , &dwID) の(LPVOID)hWnd を、副スレッド(ThreadFunc)に引数として渡しているから、つまり、主スレッドと副スレッドは、(LPVOID)hWnd だけがメモリを共有する、ということでしょうか? 主スレッドと副スレッドでメモリを共有すると、どんなメリットがあるのでしょうか? 4)マルチスレッドはこういう時に使うとよい、 というような大まかな判断基準があれば教えて下さい。 分かり辛い質問で申し訳有りません。宜しくお願い致します。 |
|
困り度:
|
||
| 質問投稿日時: 08/05/17 00:37 |
||
回答 |
|
| ANo.7 | 超単純な話ですよ。単純に考えてください。 完全に独立した処理を行うスレッドを生成し同期自体を必要としない場合は処理の早さはCPUコアの数(スレッドの数)に比例し向上しそうですよね?ですが、スレッドAさんが共有のメモリを操作している時はBさんは待機しなければならないという状況があったとします。(各人が30回ノルマのもち付きみたいなイメージでもいいです・・・ちょっとちがうか?)この時、この待ち時間と独立した処理に掛かる時間が、 待ち時間<<独立した処理に掛かる時間 だったら、CPUコアの数の分だけ効率化できそうでしょう?(もちつきは無駄だらけって事になるが・・・。)左の様なロスを極力少なくしようとプログラムする場合、元々の処理の時間が重い案件の法がN倍の限界値に近付け易そうでしょう?という意味です。同期処理と書いた方が的確でしたか? |
|---|---|
| 回答者:POTATO_XP | |
| 種類:回答 どんな人:経験者 自信:自信あり |
|
| 回答日時: 08/05/20 22:35 |
|
| |
| この回答へのお礼 | 何度も有難う御座いました。 分かりやすい説明です。 やっと理解できました。 今、VCでマルチスレッドの簡単なプログラムを組んでいるのですが、 意にそぐわない動きをして、首をひねっている状態です。 別の質問でまたお聞きするかもしれませんがその時は宜しくお願い致します。 どうも有難う御座いました。 |
回答 |
|
| ANo.6 | 違います。厳密には・・・。 CPUのコアの数と同じ数の副スレッドを生成するのは正しいです。ただ、それ以上に生成すると、必ずと言って良いほど発生する副スレッド間での共有メモリの排他制御等、単純ループに無い複雑な制御を律儀に行い実質の計算時間と通信に掛かる時間の割合が逆転してきます。 “重い処理”と書いたのはそういう理由です。プロセス間通信に掛かる時間と、分担したい処理の総時間の割合で、後者を如何に高くするかが注目のポイントで“重い処理”ほど簡単です。例を挙げるなら、動画像のエンコードの様な場合とかでしょうか?GA(遺伝的アルゴリズム)の計算とかにも簡単に適用できそうに思います。 補足でした。再質問受け付けます。 |
|---|---|
| 回答者:POTATO_XP | |
| 種類:回答 どんな人:経験者 自信:参考意見 |
|
| 回答日時: 08/05/20 00:25 |
|
| |
| この回答への補足 | どうもありがとう御座います。 以下の文、もう少しだけ教えて頂けませんでしょうか? >プロセス間通信に掛かる時間と、分担したい処理の総時間の割合で、後者を如何に高くするかが注目のポイントで“重い処理”ほど簡単です。 後者を如何に高くするか、と、 ”重い処理”ほど簡単 というのが良く分かりませんでした。 何度もすみません。 時間があるときで結構なので、宜しくお願い致します。 |
| この回答へのお礼 | この回答にお礼をつける(質問者のみ) |
回答 |
|
| ANo.5 | こんにちは。 4) についておすすめのマテリアルがあります。 Multithreading - The Delphi Way. Martin Harvey Delphi を言語処理系に用いて、マルチスレッドプログラミングが必要なとなる状況、要素技術、適用事例を、軽快な口語調で説明しています。 回答者は、Windows の Synchronization 技術を、このガイドと msdn で学びました。文中で使用されている図は分かりやすく、デザインやデバッグ時に役立ちます。(UML のシーケンス図とは異なりますが) |
|---|---|
| 回答者:iriyak | |
| 種類:アドバイス どんな人:経験者 自信:参考意見 |
|
| 回答日時: 08/05/18 16:14 |
|
| |
| 参考URL: | http://www.eonclash.com/Tutorials/Multithreading/MartinHarvey1.1/To... |
| この回答へのお礼 | 情報どうも有難う御座います。 早速見て見ましたが、英語なんですね。 かなり時間がかかりそうですが、少しづつ読もうかなあと思っております。 どうも有難う御座いました。 |
回答良回答20pt |
|
| ANo.4 | まず、重要な概念を一つ。 いままでは、あるZさん一人で仕事を片付けなければなりませんでした。これが、関数をループで処理する状態。 数年後は、チームのリーダーZさん、メンバーのAさん、Bさん、Cさんがいたとして、同じような書類を大量に作成する仕事があったとします。当然Zさんは、A、B、Cさんに均等に指示を出し文書整理をさせ仕事を早く終わらせようとします。これが分散処理で、関数をスレッドとして呼び出す状態。 このZさんが主スレッド。A、B、Cさんが副スレッドです。ここで文書整理を行う為のパソコンが2台あったとしてこれがCPUコアに相当します。パソコンの台数以上に人増やしたって変わらないでしょう?もちろんリーダーとの報・連・相が必要な場合があり、それがプロセス間通信に相当します。コレを少なくすればするほど仕事は捗ります。 まぁ、簡単にはこういうものです。どういう処理を書けばよいか見えてきましたか? マルチスレッドでの処理はCPUコアが複数ある時に真価を発揮します。仮想でもOK。重い処理を繰り返し行う様な場合に分散処理を使うと効果を得やすいです。シングルコアなのに繰り返し処理を分散処理に変えたって、かえって処理が遅くなるだけですよ。Core2 Quadで試してみましょう。それでも、コアの数は高々4つなので飛躍的な効果というのは期待出来ないものです。 また、リアルタイム特有のタイミング的なバグの心配も必要になり、この辺は組み込みに少し似ているかなと思います。 |
|---|---|
| 回答者:POTATO_XP | |
| 種類:回答 どんな人:専門家 自信:自信あり |
|
| 回答日時: 08/05/18 13:17 |
|
| |
| この回答へのお礼 | 回答どうも有難う御座います。 私は少し勘違いしていた様です。 CPUコアが一つだった場合、副スレッドに重い処理を割り当てると、他の制御に影響が出ることはないものの、結局その重い処理を後回しにしているだけなので、最終的にはむしろマルチスレッドの方が時間がかかってしまう、という風に理解しましたが正しいでしょうか? まずは、簡単な処理から試してみようと思います。 丁寧に説明頂き有難う御座いました。 |
回答 |
|
| ANo.3 | > 同一プロセス(アプリケーション)内に複数の関数を持つ場合、その関数同士は引数や戻り値で値を渡したりグローバル変数を使ってやりとりしますが、親スレッドと子スレッドのメモリ空間の関係はそれと同じということでしょうか? 子スレッドとして呼び出される関数の引数/戻り値の型が固定されていたり、引数/戻り値を受け渡しする方法がちょっと特有ではありますが、それ以外のやり取りは同じです。 ↓この辺とかに書いてあります http://msdn.microsoft.com/ja-jp/library/cc429080.aspx http://msdn.microsoft.com/ja-jp/library/cc429382.aspx あと、プロセスについては #2 の方が訂正してくれた通りです。 # "メモリ上で"動作中のアプリケーション"のイメージ" くらいは端折らないほうが良かったですね…。 ## 「インスタンス」を理解しているのであれば Wikipedia に書いてあるとおりの言い方が一番理解しやすいかも。 |
|---|---|
| 回答者:_himajin_ | |
| 種類:アドバイス どんな人:一般人 自信:参考意見 |
|
| 回答日時: 08/05/17 12:56 |
|
| |
| この回答へのお礼 | 情報どうも有り難う御座います。 うーん、ちょっと難しそうですね。 実は今、ブロック崩しもどきのショボイプログラムを試行錯誤しながら組んでいて(VC)、そこでタイマを使っているのですが、もっとおしゃれな方法がないかなあと思っていたら、マルチスレッドという言葉にぶつかりました。が、全く理解出来なかったので質問させて頂きました。折角皆様に教えて頂いたので、タイマの部分をマルチスレッドに変えてやってみようと思います。 色々教えて頂き、有難う御座いました。 |
回答良回答10pt |
|
| ANo.2 | (1)タスクはメインフレームの世界では意味が異なりますが、 PCではプロセスと同意義です。 タスク=プロセス≠実行ファイルです。例えば、IEを2個立ち上げたとします。 同じ実行ファイルから起動しましたが、プロセスは別です。別のページをみられ ますし、片方を閉じたからと言って、もう一方が閉じると言うことはありません。 (2)スレッドとはコンピュータの制御権です。普通、プログラムが実行されると、 OSから制御権がMainに渡されます。そこからはプログラムに記述した通りに 動くわけです。この制御権をもう一個取得し、別のメソッドを走らせるのが マルチスレッドという訳です。スレッドの切り替えはOSがやっています。 私の知る限り、スレッドの切り替えの設定はユーザプログラムから出来ません。 但し、優先度を変更したり、サスペンド(休眠)したりは出来ます。 (3)URLのプログラムではThreadFuncが副スレッドが走るメソッドで、それ以外は 主スレッドが走るメソッドです。その例にはありませんが、共通のメソッドを作る ことも勿論、可能です。 (4)>マルチスレッドは親プロセスのメモリ空間を共有します 他のプロセスのメモリは参照/更新することはできません。これに対し、 大域変数は主スレッド、副スレッドの両方から参照できますし、共通メソッドを 呼び出し合うことも出来ます。これはスレッドが同じプロセスに属しているからです。 (5)マルチスレッドが有効になるところは色々あります。 簡単な例はファイルのコピーです。普通ですと、入力→出力→入力→出力…と なりますが、マルチスレッドでは出力と同時に次の入力を行うことができます。 理論上はシングルスレッドでやるときの半分の時間で完了します。 実際に、かなりの時間短縮につながります。 【ファイルコピーのシーケンス】 シングル: 入力→出力→入力→出力→入力→出力→入力→出力 マルチ: 入力→出力→入力→出力 入力→出力→入力→出力 |
|---|---|
| 回答者:nda23 | |
| 種類:アドバイス どんな人:専門家 自信:参考意見 |
|
| 回答日時: 08/05/17 12:13 |
|
| |
| この回答へのお礼 | 詳細に説明して頂き、有難う御座いました。 今迄の断片的な知識が、一つに繋がった感じです。 マルチスレッドは危険だとどこかのサイトに書いてあったので訳も分からぬまま信じてしまったのですが、便利なのですね。 良く分かりました、感謝です!! |
回答 |
|
| ANo.1 | とりあえずWikipediaの「スレッド_(コンピュータ)」と「マルチタスク」をどぞ。他の用語も関連項目に大抵解説があります。 http://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89_(... http://ja.wikipedia.org/wiki/%E3%83%9E%E3%83%AB%E3%83%81%E3%82%BF%E... 以降、正確ではないけど大外れでもないはず…って程度のかなり怪しい概要です。 # _himajin_ はこんな感じに理解してるんだな、って程度の参考情報として捉えてください。 1) 「タスク」は結構あいまいな用語ですが、ここでは「プロセス」として扱ってるようですね。 「プロセス」は動作中のアプリケーションです。 「スレッド」は同一プロセス内で同時に動く1本の関数の流れです。 糸(=Threadの直訳)をイメージすると理解はしやすいかも。 「主スレッド」は「副スレッド」を作成したスレッドのことです。 # 主/副よりは親/子と言ったほうが関係がわかりやすいので以降親子にします。 2) WinMain で CreateThread したなら、WinMain が動いているスレッドが親スレッドです。 # WinMain のようなプログラム開始時に呼ばれる関数は常に親スレッドなので、これを特別にメインスレッドと呼ぶ人もいます。 ## 単純に main / WinMain のスレッドだから、かも知れませんが。 切り替えタイミングはOSに依存しますが、最近のWindowsならOSが自動的に行います。 3) hWnd は ThreadFunc の引数です。 hWnd に限らず、親スレッドと子スレッドは同一プロセスなのでメモリ空間を共有しています。 # 元記事は親プロセス、ではなく親スレッドの間違いじゃないかなぁ メモリ空間を共有していると、親スレッドと子スレッドの間で通常通り変数のやり取りなどができます。 たとえば hWnd のように引数で渡せばその中身は双方で同じものが見られますし、グローバル変数も両方から同じものが見られます。 # 同時に操作できてしまうので Mutex だとかが必要になってくるんですがそれはとりあえず置いときます これが別プロセス(別なメモリ空間)だとRPCやファイル経由とかにしないと見られません。 4) 〜〜〜しながら〜〜〜もする、と言うときに使うと良い、と言うか使わざるを得ないです。 |
|---|---|
| 回答者:_himajin_ | |
| 種類:アドバイス どんな人:一般人 自信:参考意見 |
|
| 回答日時: 08/05/17 02:45 |
|
| |
| この回答への補足 | どうも有難う御座います。全くもってちんぷんかんぷんだったので、非常に参考になりました。すみません、ウィキペディアチェックしていませんでした。 もう少しだけ教えて頂けませんでしょうか? ”メモリ空間を共有していると、親スレッドと子スレッドの間で通常通り変数のやり取りなどができます” なのですが、同一プロセス(アプリケーション)内に複数の関数を持つ場合、その関数同士は引数や戻り値で値を渡したりグローバル変数を使ってやりとりしますが、親スレッドと子スレッドのメモリ空間の関係はそれと同じということでしょうか? 初歩的な質問ですみません。 |
| この回答へのお礼 | この回答にお礼をつける(質問者のみ) |