プロが教えるわが家の防犯対策術!

いつもお世話になっております。
今回はマルチスレッドプログラムについてお聞きしたいです。

マルチコアCPUを使ってたとえば下記のようなことをしたいときに
for (int i = 0; i < 1000000; i++)
{
sum += i;
}
このまま計算するよりもいくつかスレッドを作って、計算量を分散させてから最後に足してやるほうが早いと思いまして、
現在Core2Quadが手元にありましたのでスレッドを4つ作って
スレッド1で0から250000まで
スレッド2で250001から500000まで
スレッド3と4も同様にして実際にやってみたのですが
スレッドなしの状態よりも倍くらい時間がかかってしまうようになってしまいました。
計算結果は同じになり、CPU使用率もシングル時が25%、マルチ時が100%になっているので意図したようにはできていると思います。
GetProcessAffinityMaskを使って、各スレッドにひとつづつコアを割り当てても同様でした。
実際に時間が4分の1に近くなると思っていたのですが2倍かかってしまったので不思議です。
どなたか上記のことを思惑通りに動かせそうな方法をご存知の方はご教授願います。
プログラムは全部は無理ですが重要そうなところは下記のとおりです。

スレッド作成部分
{
  DWORD dwStart = ::timeGetTime();

  _thread_handle[0] = (HANDLE)::_beginthreadex(NULL, 0, thread_first, NULL, CREATE_SUSPENDED, &_thread_first_id);
  _thread_handle[1] = (HANDLE)::_beginthreadex(NULL, 0, thread_second, NULL, CREATE_SUSPENDED, &_thread_second_id);
  _thread_handle[2] = (HANDLE)::_beginthreadex(NULL, 0, thread_third, NULL, CREATE_SUSPENDED, &_thread_third_id);
  _thread_handle[3] = (HANDLE)::_beginthreadex(NULL, 0, thread_forth, NULL, CREATE_SUSPENDED, &_thread_forth_id);
  for (int num = 0; num < 4; num++)
  {
    ::ResumeThread(_thread_handle[num]);
  }
  ::WaitForMultipleObjects(4, _thread_handle, TRUE, INFINITE);
  for (num = 0; num < 4; num++)
  {
    ::CloseHandle(_thread_handle[num]);
  }
  DWORD dwEnd = ::timeGetTime();
}

各スレッド部分
{
HANDLE hCurrent = ::GetCurrentProcess();
DWORD pamask, samask, patmp = 0;
int nRet = ::SetProcessAffinityMask(hCurrent, 0x0001);
::GetProcessAffinityMask(hCurrent, &pamask, &samask);
DWORD dwStart = ::timeGetTime();
_result1 = 0;
for (int multi = 0; multi < _multi; multi++)
{
  for (DWORD i = 0; i < 100000/4; i++)
  {
    _result1 += i;
  }
}
DWORD dwEnd = ::timeGetTime();
time1 = dwEnd - dwStart;
::_endthread();
return 0;
}

開発環境は
WindowsXP SP3
VisualStudio6.0 ATL/WTLです。

A 回答 (7件)

もうすでに解決されてると思いますが、おそらくこうではないでしょうか?



× SetProcessAffinityMask
○ SetThreadAffinityMask
    • good
    • 0

SetProcessAffinityMaskってスレッドじゃなくプロセスに対するものではっきり言って別物なんだけども、本当にそのコードなんですか?


Setの後にGetProcessAffinityMaskしてる意味もわかりませんし

この回答への補足

補足です。
SetProcessAffinityMaskについては理解が足りていませんでしたので、もう一度勉強します。
GetProcessAffinityMaskをしているのはちゃんと割り当てられているか確認するだけですので意味は特にありません。

補足日時:2009/04/22 23:13
    • good
    • 0

省略した箇所に原因が潜んでいることが多いので、実検証できるソースを提示しないとなかなか解決には至らないと思います。


以下気になったこと。

(1) シングルスレッドのソースと比べ、マルチスレッドの処理で以下のfor文が追加されていますがなんでしょう。

for (int multi = 0; multi < _multi; multi++)

(2) _beginthreadex で開始したら、終了は _endthreadex です。

(3) CriticalSection, Mutex など排他制御はやってませんか ?

この回答への補足

補足です
(1)足し算を行う回数です。何回足すかを指定できるようにしています。
転載のとき削り忘れました。

(2)修正しましたが変化なしでした。

(3)排他はしておりません。4つの和を最後に足して、シングルのときの結果と比較しております。

補足日時:2009/04/22 23:10
    • good
    • 0

スレッド生成とか同期のコストに比べて演算負荷が軽すぎるのでは?


もう一桁二桁上げてどうなるか見てはどうでしょう。

この回答への補足

ご回答ありがとうございます。

もう一桁二桁というか、足すfor文の回数を1回から16回繰り返しまでできるようになっているのですが、妥当に回数倍かかってしまいました。

補足日時:2009/04/22 23:14
    • good
    • 0

私の処理では、並列にするとスピードアップしました。


始め、関数として普通に呼び出します。
その次、ワーカスレッドへポインタを渡し、上記関数を実行しました。
すると俄然スピードが上がりました。

ただ、その調子で32個もスレッドを組んだお陰で、やたら不安定なプログラムになりました。
まぁ、今回は勉強だと思って、作り直したらと言われています。
スレッドは、作って見ないと解らないところがあります。やりすぎると、大変な目にあいます。ご注意ください。
ページフォールトは少なくなるようにしたほうがいいですよ。
(タスクマネージャでモニター可能)
    • good
    • 0

推測の域を出ませんが、以下のような理由では?


整数の単純加算のように、待機の全く発生しない処理ではマルチ
スレッドによる恩恵は殆どありません。むしろ、制御のための
オーバーヘッドが原因になっているのではないでしょうか。
ファイル入出力や通信など、自CPU以外の相手がある場合、相手の
動作完了までWaitがかかります(つまり、待機がある)。この
待ち時間を利用して、別の処理をするという時には恩恵があります。
大容量のファイルのコピーなどを題材にして実験してみてください。
    • good
    • 0

間違っているかもしれませんが ・・・


制限のかけ方を間違っているのではないでしょうか

4コアならば
1番目のスレッドは
::SetProcessAffinityMask(hCurrent, 0x0001);
2番目のスレッドは
::SetProcessAffinityMask(hCurrent, 0x0002);
3番目のスレッドは
::SetProcessAffinityMask(hCurrent, 0x0004);
4番目のスレッドは
::SetProcessAffinityMask(hCurrent, 0x0008);
といった具合にすればコアごとに処理すると思います

すべてのスレッドで
::SetProcessAffinityMask(hCurrent, 0x0001);
としてしまうと 1番のコアのみで処理するのではないでしょうか

当方のCore2Duoですと
::SetProcessAffinityMask(hCurrent, 0x0001);
の場合コア1のみしか使われないようです

この回答への補足

ご回答ありがとうございます。

指摘の件ですが実際のものでは指摘のように指定しております。
説明不足で申し訳ありません。

補足日時:2009/04/20 02:26
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!