staticでないメンバ関数をスレッド化したい

[戻る]
ゆん 2011/08/03(水) 17:29:36
超初心者です。初歩的な質問ですみません。
スレッド関数としてstaticでないメンバ関数を呼び出したいのですがどのようにすれば可
能でしょうか?

wclrp 2011/08/03(水) 18:09:37
まずは今まで通りstaticメンバ関数をスレッド関数にする。

それにデータを渡せる引数があるよね。
それにスレッドで実行させたいメンバー関数のオブジェクトを渡す。

static関数から、staticでないメンバ関数を呼び出す。

以下はイメージです。そのまま動くわけではない。

unsigned __stdcall StaticThreadProc(void * pParam)
{
    CHoge * pHoge = (CHoge *)pParam;
    return pHoge->MemberThreadProc();
}

CHoge hoge; //これはスレッド実行中存在すること

hTh = (HANDLE)_beginthreadex(NULL, 0, StaticThreadProc, &hoge, 0, &thID);

これで、StaticThreadProc経由して、hoge.MemberThreadProc();が
新スレッドで実行される。

ゆん 2011/08/04(木) 10:02:07
wclrp さん
提示して頂いた方法で実装できました!
ありがとうございました。

他にスレッド関係で質問です。
mainでfor文などでくるくる周ってその度にスレッドをコールします。
スレッドには、for文のインデックスを渡し、その値毎に処理を変えたいのですが、同時
に同じスレッドを複数コールする場合、おかしな動きになってしまいます。
スレッドでこのような処理を行うのはふさわしくないのでしょうか?

wclrp 2011/08/04(木) 11:51:24
同じスレッド関数でスレッドを2つ作成しても問題ないよ。

<話が変わる>

そもそも別のスレッドって関数コールみたいな感覚では呼ぶことできないから
どういうことなのかしら。
forループでスレッドを作っている?
作れるスレッド数には限界があるはず。

<話が変わる>

例えば_beginthreadexからリターンされてきても
まだThreadProc()が実行されてきてないこともあれば
ThreadProc()内でエラーが起きてて既にスレッドが終わってた
なんてこともある。

スレッドはデバッグ大変だから
ちょっとでも引数や変数の値が変かチェックをいたるところに仕込んで
ファイルにログ出すとかかなあ。

<話が変わる>

本来スレッドごとに別のものにしないといけないのに同じ変数(その他)を
複数のスレッドで使っているとか。

同じ変数(その他)を(メインスレッドも入れて)複数のスレッドで
読み書きしているのに排他制御していないとか。

ryo 2011/08/04(木) 13:14:07
>スレッドには、for文のインデックスを渡し、その値毎に処理を変えたいのですが、同時
>に同じスレッドを複数コールする場合、おかしな動きになってしまいます。
おかしな動きとは?

PATIO 2011/08/04(木) 13:39:36
書かれている内容だけでは何をやろうとしてスレッドを
使っているのかが読み取れませんけれど、

よくあるパターンとしてウインドウを表示しているメインスレッドに
とても重い処理があると「応答なし」状態になってしまうので
応答なし状態にしない為に重い処理をワーカースレッドにして
サブスレッドとして動かす事で応答なし状態を回避するという事が
あると思います。
基本的にウインドウを表示するタイプのアプリケーションで
ボタンを押す等のウインドウメッセージで起動される関数内に
長くかかる処理(繰り返し回数が多いループ等)を置くのは
実装として良くないので、こういった処理はワーカースレッド化する
対象にする事が多いです。

で、ループ部分その物をワーカースレッド側に追い出すとかは
考えられないのでしょうか?
メインスレッド側で何らかの表示が必要なのであれば、
その情報をワーカースレッドの方からメインスレッドに通知する
仕組みを作って表示のみをメインスレッドでさせた方が
処理の切り分けとしてはすっきりすると思います。

あと、ワーカースレッドをどのように使おうとしているのかと
いう話もあります。一つの処理が完了するとスレッド自身も
終わってしまい、処理をする度にスレッドを起動するやり方もあれば、
最初の処理の時にスレッドを起動して、処理が終わったら
スレッド側は待ちに入る。二回目以降の処理に関しては
既に起動済みのスレッドに対して処理を依頼する。
と言う方法もあります。
但し、この場合は待機しているスレッドを終了させる為の
仕組み立てを用意する必要が有りますけれど。

で、前者で処理する場合、毎回毎回、ワーカースレッドを起こす事に
なりますが、その時点で前のスレッドが終ってなかったらどうするの?とか、
終っていなくて良いとした時にリソースの競合は起こらないの?とか、
考える事はたくさんあると思います。

> mainでfor文などでくるくる周ってその度にスレッドをコールします。

と言う部分が毎回スレッドを起動するイメージなのか、同じスレッドに
対して指示を与えたいという話なのかで仕組み立ても変わってきますから
シーケンス図とかでメインスレッドとサブスレッドの関係をきちんと
整理した方が良いかもしれません。

既にwclrpさんが書かれている通り、スレッドは関数のように必要なタイミングで
毎回呼び出せば良いというようなものでは無いのでもう少し突っ込んだ検討が
必要だと思いますよ。呼出し後は並行して動作しているイメージなので
呼出から帰ってきたから処理が終っていると言う話にはなりません。

PATIO 2011/08/04(木) 13:48:56
ちょっと気になった事。

超初心者と書かれていますけれど、C++言語の文法とか
クラスの考え方とかオブジェクト指向の基本的な知識とか
そういう部分は大丈夫なのでしょうか?
初心者ですとか超初心者ですとか書かれるよりも
どの程度の事までなら自力で出来ますとかの方が
掲示板で質問する時は意味がある内容になると思いますよ。

C++の文法の所の話からとかなると結構大変ですし。

tenteku 2011/08/04(木) 14:31:31
for文ってループに使うわけでインデックスで処理を変えたいものを
あえてfor文で処理するメリットがあまり思い浮かばないとか言ってみるテスト

関数アドレステーブルの配列とかのほうがマシと思うわけですが
どういう状況でどういう文法を使用するとうまくプログラムが組めるとかの経験がないう
ちから
スレッドに手を出すと痛い目を見ます。経験上。
興味本位でやってみたいだけなら止めはしませんけど

仲澤@失業者 2011/08/08(月) 11:27:49
想像してみますと、
1.AfxBeginThread()等でスレッド関数StaticThreadProc()を起動した。
2.StaticThreadProc()は、渡されたクラスインスタンスのメンバ関数
 MemberThreadProc( 0)をコールした。
3.一方、スレッドを起動した側では、次のようなコードになってる
 AfxBeginThread(...); // スレッドの起動
 for( int i=1 ; i<1000 ; i++){
  MemberThreadProc( i); // メンバのスレッド関数をまた呼んでる
 }
なんて事になってないでしょうか。
もし、これに近いことをやっているとすると、一般的には間違いです。
スレッド、又はスレッド関数に、外部から何らかの「状態変化」を伝えるには、
volatileなメンバ変数を経由して伝えるか、イベント等の「同期オブジェクト」
を使います。
このあたりは大丈夫ですか。

古いスレッドには追加発言できません。