• ベストアンサー

マルチスレッド化。

今とても大きな配列を使用し、長時間処理をするプログラムを組んでいます。元々処理時間に1時間を要するプログラムを2分で処理を完了するまでに仕上げました。 しかし、探究心はおさまらずもう少し高速化に挑みたいと考えています。 過去に「猫でもわかる」のSDK第1章と2章を学び、マルチスレッドのプログラムをSDKで組んだことがあります。それを利用してマルチスレッド化を実現したいと考えています。 言語はCでVisualStudio2005を使用しています。 *疑問1   SDKの場合WinMain関数とプロシージャからの実行で_beginthread関数を記述すれば処理が開始されます。 Cでもmain関数内に記述すれば、SDKと同様に処理できるのでしょうか? *疑問2 _beginthread関数の引数に関してです。 第1引数にvoid型のスレッド関数、第2引数に0?、そして第3引数にはスレッド関数に渡すデータの引数を記述すると把握しているのですが、渡したいデータは複数あり、***型と**型、それに変数を数個とスレッド関数に渡したいデータだらけなのですが、どのように記述すればよいでしょう? *疑問3 2つのスレッドを作成しようと考えていますが、その2つのスレッドで1つの大きな配列を共有して処理したいと考えています。 そのため、スレッド間の同期が必要になるわけですが同期の種類にもクリティカルセクションやミューテックス、イベントと豊富でどれを使用すれば良いのか迷ってしまいます。厳密に同期を取り処理をするにはイベントが一番良いと考えています。 これらの疑問に答えられる方はアドバイスをよろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.3

>*疑問1  可能です。 beginthread関数はライブラリ関数です。 SDKなどに依存することはありません。 >*疑問2 既に出ていますね。 構造体に必要なものを纏めて渡しましょう。 >*疑問3 ここが一番疑問に思えるところです。 今回『高速化』ということですが、スレッドを使用し、排他すると言うことは、(本質的には)誰かが使っている間はそれ(今回の場合、共有される配列)を使わないということが大前提です。 この配列が複数あって、これらをスレッドごとに処理するなどは アリかもしれませんが、1つの配列を複数のスレッドで処理するのは あまり効率がよくないと思います。 本当に意味がある改造か、もう一度考えたほうが良いでしょう。 排他オブジェクトについては、イベントであろうと、ミューテックスであろうと、セマフォであろうと、名前無しであれば、クリティカルセクションで事足ります。用は、『プロセス間で排他が必要か』ということです。 特に必要ないならば、初期化のエラーチェックを省けるので クリティカルセクションをお勧めします。 beginthreadはライブラリ関数を使用すると、 メモリリークが発生する可能性がある既知の問題を抱えています。 Windows環境でスレッドを使うならば_beginthreadexを使用することを お勧めします。

Mr_tenten
質問者

お礼

返答ありがとうございました。 回答者No2さんの返答にも書きましたが、aris-wizさんのおっしゃられるとおり、マルチスレッド化を高速化のために使用する場合、排他制御は足を引っ張る処理になってしまいました。 アドバイスを参考にさせてもらい、まず_beginthreadex関数を使用して実装しました。そして処理に必要な配列ですが、一応メモリ上には乗る大きさとわかり同一の配列を二つ用意し、それぞれのスレッドに配列を割り当て排他制御を除去して処理をしたところ、2分30秒で処理をしていたところ1分30秒で処理を完了することができました。 自分の質問に2分で処理を行うまでに高速化を行ったと書きましたが実際は2分30秒かかっていたのです。 1分の高速化はとても大きなものでした。 1つ気になるのはやはりメモリの使用量ですね。今回のプログラムでは約400MBも使用してしまうので、512MBのPCならスラッシングが起こってしまい処理が遅くなってしまいましたが、1GB以上なら何とか高速に処理することができました。今後メモリを節約し、高速化を実現できるように努力していきたいと思います。 ありがとうございました。

その他の回答 (2)

  • rabbit_cat
  • ベストアンサー率40% (829/2062)
回答No.2

疑問1 Yes 疑問2 渡したい引数を、構造体にまとめて、構造体のポインタを渡します。 疑問3 同期に何を使うのがいいかは、場合によります。 もし、頻繁に同期する必要があるなら、ミューテックス、イベントといった重い処理を使わないで、なるべくクリティカルセクションで済ましたほうがいいでしょうし、仰るとおり厳密に同期がとりたいなら(多少重くても)イベントを使うべきときもあります。 http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/jpdndllpro/htm/metrsect.asp

Mr_tenten
質問者

お礼

返答ありがとうございました。 回答者No1の方の返答にも書きましたが、_beginthread関数では失敗してしまったため_beginthreadex関数で再実装したところうまく動いてくれました。 そして気になる排他制御ですが、イベントなどは重いということなのでクリティカルセクションを使用してみましたが、マルチスレッドにたいして期待していた性能を引き出すことができませんでした。 やはり、処理速度や効率の向上にはスレッドそれぞれに作業用データを渡し、排他制御を取り入れないほうがぜんぜん早い気がします。 一応排他制御を行わない結果を上の回答者さんの返答に書いておきます。 ありがとうございました。

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.1

1. <process.h>や<windows.h>などを適切に使えば可能。 2. 複数データを格納できる構造体を作り、構造体のポインタとしてvoid*に渡す。  (定石なので、マルチスレッドについて調べればサンプルもたくさん見つかるはずです) 3. 同期の取り方が複数あるのは、それぞれに「トレードオフ」があるからです。  適切な部分に適切なものを選択するためのものであって、  向いている用途、向いていない用途がそれぞれありますので、  「この場合、イベントがいい」ということはあっても、  「常にイベントがいい」とかいうことはありえません。  もっと情報がないと、どれが向いているとかはいえません。 ちなみに、マルチスレッド化するうまみがある処理(並列可能など)ですか? マルチスレッド化に向くもの向かないものもありますし、 向く形に設計を組みなおさないといけないケースなどもあります。 処理によってはむやみにマルチスレッドすると遅くなる可能性もありますのでご注意を。

Mr_tenten
質問者

お礼

返答ありがとうございました。 ようやく組みあがりました。 当初_beginthread関数を使用してマルチスレッド化を行おうと考えていました。そして実装してみたところなにやら不明なエラーが・・・・ 排他制御は完璧にしているにもかかわらず、配列のポインタをアクセスするところで停止してしまいました。 原因が不明なので次に_beginthreadex関数で再実装してみたところうまく動きました。 ありがとうございました。

関連するQ&A

専門家に質問してみよう