SetTimerを別スレッドで処理する方法 – 固定ページ 2 – プログラミング – Home

SetTimerを別スレッドで処理する...
 
通知
すべてクリア

SetTimerを別スレッドで処理する方法

固定ページ 2 / 2

紅'
 紅'
(@紅')
ゲスト
結合: 17年前
投稿: 48
 

勘違いだったのですね。ごめんなさい。

もともとは描画処理などの影響で通信処理が規則正しく開始できない、って
問題なのでしたよね。雑な考え方をしていいなら、周期イベント
(メッセージ)を発生させるためだけのスレッドを自前で作ってみるとか。

試していませんが、非表示のモードレスダイアログを通信処理専用に作って、
そこからイベントを貰うか、そのクラスに処理を埋め込むとか。


返信引用
ふー
 ふー
(@ふー)
ゲスト
結合: 23年前
投稿: 28
 

唐突に、基本のあたりを書いてみます。
UIスレッド(ユーザー インターフェイス スレッド)とは…

Windowsのメッセージキューを持っているスレッドのこと。
ウィンドウではなくメッセージキューが本質的。
必ずしもウィンドウを持っている必要はない(いや、ありましたっけ?)
当然ながらウィンドウアプリのメインスレッドはUIスレッドの一種。

メッセージキューには、PostThreadMessage や PostMessage で
メッセージが投函(POST)される。
UIスレッドはメッセージループを回して、メッセージキューに入ってきた
メッセージをどんどん受け取って処理する必要がある。
(MFCではそのループはMFCのソースのどこかにあります…)

TimerProcやWM_TIMERはメッセージキューを利用しているので、
UIスレッドでなければ利用できない。

私の認識ではこんなところですね。
Windowsプログラミングの基本なんですけど、理解するまで時間がかかるとこ。


返信引用
麩
 麩
(@麩)
ゲスト
結合: 17年前
投稿: 95
 

>2. OnTimer()ハンドラで、別スレッド対しに
>PostThreadMessage(..WM_TIMER..)
無意味かと思いますが。
それだとメッセージポンプが動くまで処理されない筈です。

>KickGetData() の実行時間が実質0であれば、ずれていかないと思うが。
>::SetEvent(event_awake_aquire_thread);
>位の実装にしなはれ、ということ。この程度なら必要時間は実質0だろう
プロセス又はスレッドをまたぐので排他処理がOSの挟まる可能性も有るとおもい
ます。
あと、自分しかプロセスがいないなどと考えていると痛い目を見ると思います。
他プロセスも時間を使っていきます。

なんかで読んだ話と意識され難いがよくよく考えれば常識的な話。
・Sleepは他スレッドがCPU空きを待っている場合はそちらに切り替えるの
で、0msを指定してもそれ以上掛かる場合が普通にある。
・そもそも普通のスレッドはどんなタイミングでも割り込まれうるので、その間他ス
レッドが使った時間も考慮すべき。

SleepのMSDNの説明
「0 を指定すると、スレッドは、実行の準備ができている同じ優先順位のほかの
スレッドに残りのタイムスライスを譲ります。」
0以上でも当然譲っていると考えて、指定した時間で処理が帰ってくることは全く
期待できません。
顕在化するのは環境依存ですが、少なくともSleep前後の処理での何ミリ秒か
ずつは蓄積します。

時間当たりの呼び出し回数を守りたいのならば、絶対に自分で現在時刻を監
視すべきです。
時間当たりの呼び出し回数が保障されるものも有るはずですが、そうと明記され
ない限りはそれを期待してはいけません。


返信引用
FUKU
 FUKU
(@FUKU)
ゲスト
結合: 17年前
投稿: 73
 

>>2. OnTimer()ハンドラで、別スレッド対しに
>>PostThreadMessage(..WM_TIMER..)
>無意味かと思いますが。
>それだとメッセージポンプが動くまで処理されない筈です。

いえ処理されます。確認しました


返信引用
ITO
 ITO
(@ITO)
ゲスト
結合: 22年前
投稿: 1235
 

>>2. OnTimer()ハンドラで、別スレッド対しに
>>PostThreadMessage(..WM_TIMER..)
> 無意味かと思いますが。
> それだとメッセージポンプが動くまで処理されない筈です。

>いえ処理されます。確認しました
スレッド内の独自のメッセージループを通るのでいくらか早いのでは?

> >KickGetData() の実行時間が実質0であれば、ずれていかないと思うが。
> >::SetEvent(event_awake_aquire_thread);
> >位の実装にしなはれ、ということ。この程度なら必要時間は実質0だろう
> プロセス又はスレッドをまたぐので排他処理がOSの挟まる可能性も有るとおもい
> ます。
> あと、自分しかプロセスがいないなどと考えていると痛い目を見ると思います。
> 他プロセスも時間を使っていきます。
 イベント同期の処理は、メッセージループを通らないので処理が早いです。
 マルチスレッド処理で、スレッド同士の同期を取るときもよく使われます。
 マイクロソフトは1mS未満だと言ってますが、真実かどうかは疑問です。

> 顕在化するのは環境依存ですが、少なくともSleep前後の処理での何ミリ秒か
> ずつは蓄積します。
少なくても10mS位はかかるそうです。(マイクロソフト談)

> 時間当たりの呼び出し回数を守りたいのならば、絶対に自分で現在時刻を監
> 視すべきです。
そのとおりですね。


返信引用
rin
 rin
(@rin)
ゲスト
結合: 18年前
投稿: 112
 

こんなんダメかな

CTimeSpan span;
CTime NowTime,LastTime = CTime::GetCurrentTime();

int ExitFlag(0);

while( ExitFlag == 0 ){
NowTime = CTime::GetCurrentTime();
span = NowTime - LastTime;

if( span.GetTotalSeconds() >= 1 ){
LastTime = NowTime;
GetData();//処理
}
Sleep(10);
}

GetCurrentTimeじゃなくて、timeGetTime()使う手も
#にしても、CTime::GetCurrenTimeはなんで選択候補に出ないのだろ・・・


返信引用
麩
 麩
(@麩)
ゲスト
結合: 17年前
投稿: 95
 

>いえ処理されます。確認しました
こちらの環境か再現方法がおかしいのでしょうか、UIスレッドが停まるとタイマ処
理も停まりました。
WinXP SP2 VC++6.0 Win32プロジェクト形式「Hello World!」
(前略)
DWORD dwThr;
DWORD WINAPI ThreadProc(LPVOID lpParameter){
MSG msg;
while (::GetMessage(&msg, NULL, WM_QUIT, WM_TIMER))
{::MessageBeep(0);}
return 0;
}
VOID CALLBACK TimerProc(HWND hwnd,UINT uMsg,UINT
idEvent,DWORD dwTime){
::PostThreadMessage(dwThr,WM_TIMER,0,0);
}
(中略)
case WM_CREATE:
::CreateThread(NULL,0,ThreadProc,NULL,0,&dwThr);
::SetTimer(hWnd,10,1000,TimerProc);
/*hWnd又はNULL*/
break;
(中略)
case IDM_ABOUT:
::Sleep(10000);
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd,
(DLGPROC)About);
(後略)
エラー処理は省きました。
IDM_ABOUTを実行すると定期的に鳴っていた音が止まってしまいました。
なにか自分が勘違いしてるのでしょうか。

>少なくても10mS位はかかるそうです。(マイクロソフト談)
Sleep以外の処理って事なのでそっちではないのですが、Sleep自体酷ければ秒
単位のオーダーで遅れる場合もありうるでしょうね。
10mSづつ遅れるとしても100回ごとに1秒分遅れるわけで、1秒ごとの処理を二
分もしていれば1回分とり漏らす事になる…という計算で良いのかな。

他にCPU空きを待つのスレッドが居なければ下回る可能性はあると思ったので
試してみました。
無限ループスレッドを作ってから100回Sleep(0);を実行して前後で
GetTickCount()→1
無限ループスレッドを作らずに10000000回Sleep(0);を実行して前後で
GetTickCount()→2
結果:1→GetTickCountの差が3969。2→GetTickCountの差が10703。
よって1の場合約40ms、2の場合0.001ms以下との結果に。
GetTickCountなのは面倒だったからですが、このくらいの数値なら十分許容範
囲かと思います。

#>CTime::GetCurrenTimeはなんで選択候補に出ないのだろ・・・
#この話の場合、元々1秒単位の処理で分解能が1秒だと不安だからです。
#GetCurrenTime等だと構造体から時間計算の手間も必要で煩雑です。
#というのは建前で参考にした本がゲーム向けだったからです。
#高精度+軽量+非MFC限定とかだったのかも知れません。
#挙げなかっただけでCのtime関数などでも目的次第では十分使えます。


返信引用
FUKU
 FUKU
(@FUKU)
ゲスト
結合: 17年前
投稿: 73
 

あ、すいません。勘違いしてました。
::PostThreadMessage()では、サブスレッドの処理はされないと読めたので^^;

> case IDM_ABOUT:
> ::Sleep(10000);
UIスレッドのブロッキング中は当然メッセージポンプが動かない為
タイマハンドラは処理されませんね。


返信引用
rin
 rin
(@rin)
ゲスト
結合: 18年前
投稿: 112
 

>#この話の場合、元々1秒単位の処理で分解能が1秒だと不安だからです。
ああ、すいません。
たしかにこの書き方だと、この話題になんででないのか?って意味にみえてしまうのが
当たり前ですね

VC2005で、ソースを書いていたときCTime::まで打ったときにでる選択候補に
「GetCurrentTime」がでてこなくて、それがなぜかなとちょっと愚痴を付け加えて
しまいました。申し訳ございません


返信引用
ITO
 ITO
(@ITO)
ゲスト
結合: 22年前
投稿: 1235
 

> VC2005で、ソースを書いていたときCTime::まで打ったときにでる選択候補に
>「GetCurrentTime」がでてこなくて、それがなぜかなとちょっと愚痴を付け加えて
> しまいました。申し訳ございません
「GetCurrentTime」も対象のひとつだと思います。
ただ、
 >#GetCurrenTime等だと構造体から時間計算の手間も必要で煩雑です。
これが理由なのでしょう。
SetTimerの時間を100mS位にして時間を監視して、1秒たったらイベント出力
というてもありかなと思います。

# まぁ-今回の場合描画に凄く時間が掛かるのが問題のひとつに見えます。
# 描画処理のうち、ウインドウハンドルに関係のない部分をスレッドかして、
# 処理を早くすることも大切だと思いますね。
# OnTimer()のルーチン自体が重くなっていること自体おかしいともいえますね。


返信引用
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

可能か不可能かと言う話をするには何処までの精度が必要なのと言うのが
必ずついてまわると思います。
現状の質問にはその部分の提示が有りません。
精度が書かれていないから1msもずれる事はまかりならん
(もしくは1秒間に1000回の通知、一回たりとも違っている事は・・・)
と考えてしまうと、技術的にはNGでしょう。

Windowsでやるならかなりゆるい精度で無いと保証できないと思います。
どのくらいの精度までなら期待できるのと言う話は多分システム依存になりそう。
Windowsのタイマーの分解能以外にも間でするべき処理の重さとか色々影響が
ありそうなので。


返信引用
固定ページ 2 / 2

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました