- - PR -
スレッドの一時停止および再開について(マルチスレッド)
投稿者 | 投稿内容 | ||||||||
---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2007-01-10 11:18
通知側スレッドがSetEvent()した後も待機状態に入らずにCPUを使い続けた場合、 SetEvent()できている事から実行中なため、その後もOSから強制的に実行権を 取り上げられるまで(数msec〜10msecくらい)は動き続けます。 SetEvent()後にスレッドを終了している場合は、OSやCランタイムの後始末ルーチンが 走ったりもするので、その影響もあるかもしれません(時間を計測した事はないですが)。 甕星さんが回答されているように、他のスレッドが実行状態にある可能性もあります。 それ以外でもこの辺りの挙動の細部は実行環境のCPU数(コア数)にも影響を受けます。 SetEvent()直後にSleep(0)やSwitchToThread()を呼び出して実行権を放棄し、 実行待ち状態のスレッドに切り替わるようにすると挙動が変わるかもしれません。 #たとえ切り替えが早くなったとしてもこの方法に頼るのはお勧めできませんが。 まぁ、まれに30msかかったとしても、普通の設計ならばイベントの通知は一回の 非同期処理の中でほんの数回しか行わないはずなのでさほど影響はないでしょう。 | ||||||||
|
投稿日時: 2007-01-10 11:31
こんにちは。
実行中(RUNNING)と実行可能状態(RUNNABLE)とは違います。 実行待ちキューに並んでいるのであって、すぐに実行されるとは限りません。 | ||||||||
|
投稿日時: 2007-01-11 02:05
こんばんわ。
返信ありがとうございます。 実は、30ms以上の待機時間があると記述したのですが・・・ 私は、ソケットプログラミングを行っています。 受信と送信スレッドを生成し、パケット受信と送信のマルチスレッドにしています。 以下にプログラムを示します。 送信スレッド内は、10(とある条件です)で割った余りが0のとき、WaitForSingleObject関数によって、スレッドを無限時間待機状態にします。 次に受信スレッドにおいて、パケットを受信するとSetEvent関数により、待機状態である送信スレッドを再開させます。 この動作を頻繁に繰り返しています。 送信スレッド内の待機時間を、タイマーとしてμ秒の高精度タイマ関数であるQueryPerformanceFrequencyとQueryPerformanceCounter関数を以下のように記述し、fprintfによりファイル出力しています。 [受信スレッド] SetEvent(hEvent[0]); [送信スレッド] LARGE_INTEGER tFreq, tBefore, tAfter; DWORD thTime; QueryPerformanceFrequency(&tFreq); if(Num%10==0){ QueryPerformanceCounter(&tBefore); WaitForSingleObject(hEvent[0],INFINITE); ResetEvent(hEvent[0]); QueryPerformanceCounter(&tAfter); thTime = (DWORD)((tAfter.QuadPart-tBefore.QuadPart)*1000/tFreq.QuadPart); fprintf(fp9,"%d¥n",thTime); } 出力されたテキストファイルを見ると、値が0や0以外の整数であったりします。値が0以外の整数であることは分かるのですが、0が出力される理由が分かりません。 0は、%dで出力しているためも考えられるのですが・・・ ほかに理由はありますでしょうか? なぜ、上記のようなプログラムの記述をしているかと申しますと、 送信スレッドの待機時間を計測するのではなく、RTT(ラウンドトリップ時間)の計測を行いたいというのが主たる目的です。送信スレッドが待機状態になり、受信スレッドでパケットが受信されSetEventにより送信スレッドが再開されるまでの時間を取得することで、RTTを計測したいと思っていたからです。 最後に、送信スレッドでタイマースタートし、受信スレッドでタイマーストップを行うということは可能でしょうか?タイマー関数はtimeGetTimeやQueryPerformanceCounterを想定しています。 よろしくお願い致します。 | ||||||||
|
投稿日時: 2007-01-11 07:26
整数演算は切り捨てになります。したがって、(tAfter.QuadPart-tBefore.QuadPart)*1000の演算結果がtFreq.QuadPartより小さければ普通に0になりますよね。そういうことではなくて?さらに指摘するとtAfter.QuadPart<tBefore.QuadPartの時に正しい結果を得られませんよね。*1000したことによるオーバーフローの発生も考慮していませんよね。
スタートやストップと言うのはどのような処理のこと?timeGetTimeもQueryPerformanceCounterも、カウンタ値を読みだすだけで、スタートという概念もストップという概念もありません。またすべてのプロセスで共有されるカウンタですので、どのスレッドから読みだしても同じカウンタ値を読み取ることになります。当然別々のスレッドで読みだした値を使って計算してもかまいませんよ。 | ||||||||
|
投稿日時: 2007-01-12 00:00
返信ありがとうございます。
大変お世話になっております。
スタートやストップとは、timeGetTime関数を用いて、以下のような記述を行なった場合を想定しています。スレッド1でタイマースタートを行い、スレッド2でタイマーをストップし、ストップ−スタートより経過時間を取得するします。 [スレッド2] DWORD timStop; timStop = timeGetTime()-timStop; //timStop値を表示 [スレッド1] DWORD timStart; timStart = timeGetTime(); 上記のような記述をしたいと思います。 ここで、timStartとtimStopはグローバル変数としておく必要がありますでしょうか? |