TNB Library
TnbThread.h
[詳解]
1#pragma once
13#include "TnbExchanger.h"
14#include "TnbStrLib.h"
15#ifndef _WIN32_WCE
16 #include <process.h>
17#endif
18
19
20
21//TNB Library
22namespace TNB
23{
24
25
26
27#ifndef _TnbDOXYGEN //Document作成用シンボル
28
29#if ! defined(_WIN32_WCE)
30 #if defined(__AFX_H__)
31 // MFC
32 inline HANDLE il_CreateThread(LPVOID pAddr, LPVOID pParam, DWORD* pThreadId)
33 {
34 CWinThread* P = ::AfxBeginThread(static_cast<AFX_THREADPROC>(pAddr), pParam, 0, 0, CREATE_SUSPENDED, NULL);
35 if ( P != NULL )
36 {
37 *pThreadId = P->m_nThreadID;
38 return P->m_hThread;
39 }
40 return NULL;
41 }
42 inline void il_ExitThread(DWORD dwResult)
43 {
44 ::AfxEndThread(dwResult);
45 }
46 inline void il_CloseThreadHandle(HANDLE h)
47 {
48 }
49 #elif defined(_MT)
50 // Cランタイム使用バージョン
51 inline HANDLE il_CreateThread(LPVOID pAddr, LPVOID pParam, DWORD* pThreadId)
52 {
53 UINT uId = 0;
54 typedef unsigned(__stdcall* P_FUNC)(LPVOID);
55 INT_PTR dw = ::_beginthreadex(NULL, 0 , static_cast<P_FUNC>(pAddr), pParam, CREATE_SUSPENDED, &uId);
56 *pThreadId = uId;
57 return reinterpret_cast<HANDLE>(dw);
58 }
59 inline void il_ExitThread(DWORD dwResult)
60 {
61 ::_endthreadex(dwResult);
62 }
63 inline void il_CloseThreadHandle(HANDLE h)
64 {
65 ::CloseHandle(h);
66 }
67 #else
68 // API 使用バージョン
69 inline HANDLE il_CreateThread(LPVOID pAddr, LPVOID pParam, DWORD* pThreadId)
70 {
71 return ::CreateThread(NULL, 0, static_cast<LPTHREAD_START_ROUTINE>(pAddr), pParam, CREATE_SUSPENDED, pThreadId);
72 }
73 inline void il_ExitThread(DWORD dwResult)
74 {
75 ::ExitThread(dwResult);
76 }
77 inline void il_CloseThreadHandle(HANDLE h)
78 {
79 ::CloseHandle(h);
80 }
81 #endif
82#else
83 // API 使用バージョン
84 inline HANDLE il_CreateThread(LPVOID pAddr, LPVOID pParam, DWORD* pThreadId)
85 {
86 return ::CreateThread(NULL, 0, static_cast<LPTHREAD_START_ROUTINE>(pAddr), pParam, CREATE_SUSPENDED, pThreadId);
87 }
88 inline void il_ExitThread(DWORD dwResult)
89 {
90 ::ExitThread(dwResult);
91 }
92 inline void il_CloseThreadHandle(HANDLE h)
93 {
94 ::CloseHandle(h);
95 }
96#endif
97
98#ifdef _DEBUG
99 // デバグ表示用
100 #ifdef __MSVCPP6__
101 #define TNB_THREADNAMEFRM1 "スレッド 0x%X"
102 #define TNB_THREADNAMEFRM2 "スレッド 0x%X [%s]"
103 #define TNB_THREADTRACETYPE "スレッド 0x%X [%s] %s。\n"
104 #else
105 #define TNB_THREADNAMEFRM1 "スレッド 'Win32 スレッド' (0x%x)"
106 #define TNB_THREADNAMEFRM2 "スレッド 'Win32 スレッド' (0x%x) [%s]"
107 #define TNB_THREADTRACETYPE "スレッド 'Win32 スレッド' (0x%x) [%s] %s。\n"
108 #endif
109#endif
110
111#endif //_TnbDOXYGEN
112
113
114
128{
129public:
130
132 CThreadStatus(void) : m_hThread(NULL), m_threadId(NULL)
133 {
134 }
135
137 virtual ~CThreadStatus(void)
138 {
139 }
140
145 operator HANDLE(void) const
146 {
147 return m_hThread;
148 }
149
154 HANDLE GetHandle(void) const
155 {
156 return m_hThread;
157 }
158
163 DWORD GetId(void) const
164 {
165 if ( ! IsAlive() )
166 {
167 return 0;
168 }
169 return m_threadId;
170 }
171
177 bool IsAlive(void) const
178 {
179 return m_hThread != NULL;
180 }
181
188 void SetOwnerHwnd(HWND hWnd)
189 {
190 m_hOwnerWnd = hWnd;
191 }
192
206 int GetPriority(void) const
207 {
208 return IsAlive() ? ::GetThreadPriority(m_hThread) : THREAD_PRIORITY_NORMAL;
209 }
210
217 bool SetPriority(int priority = THREAD_PRIORITY_NORMAL)
218 {
219 if ( IsAlive() )
220 {
221 if ( ::SetThreadPriority(m_hThread, priority) )
222 {
223 return true;
224 }
225 _GetLastError("SetThreadPriority");
226 }
227 return false;
228 }
229
238 bool PostMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0) const
239 {
240 bool r = !! ::PostThreadMessage(GetId(), message, wParam, lParam);
241 if ( ! r )
242 {
243 _GetLastError("PostThreadMessage");
244 }
245 return r;
246 }
247
248#ifndef _WIN32_WCE
255 DWORD_PTR SetAffinityMask(DWORD_PTR affinityMask)
256 {
257 DWORD_PTR r = ::SetThreadAffinityMask(m_hThread, affinityMask);
258 if ( r == 0 )
259 {
260 _GetLastError("SetThreadAffinityMask");
261 }
262 return r;
263 }
264#endif
265
266protected:
267 HANDLE m_hThread;
270};
271
272
273
316{
317 DEFSUPER(CThreadStatus);
318public:
319
340 struct IRunner
341 {
343 virtual ~IRunner(void) {}
344
346 IRunner(void) : m_canRunnable(true), m_isOnDemandSuspend(false)
347 {
348 }
349
355 bool IsRunnable(void) const
356 {
357 if ( m_isOnDemandSuspend )
358 {
359 m_isOnDemandSuspend = false;
360 ::SuspendThread(::GetCurrentThread());
361 }
362 return m_canRunnable;
363 }
364
365 protected:
366
374 virtual DWORD Run(void) = 0;
375
380 virtual void OnSetupThread(void) {}
381
386 virtual void OnExitThread(void) {}
387
388 private:
389 volatile bool m_canRunnable;
390 mutable bool m_isOnDemandSuspend;
391 CExchangerT<BYTE> m_excThreadReady;
392 friend class CThread;
393 };
394
395
396 //---------------------------
397
398
400 CThread(void) : m_pRunner(NULL), m_lastResult(0)
401 {
402 }
403
408 virtual ~CThread(void)
409 {
410 Stop();
411 }
412
420 bool SetRunner(IRunner* pRunner)
421 {
422 if ( IsAlive() )
423 {
424 return false;
425 }
426 m_pRunner = pRunner;
427 return true;
428 }
429
439 void SetOwnerHwnd(HWND hOwner)
440 {
441 _super::SetOwnerHwnd(hOwner);
442 }
443
449 DWORD GetThreadResult(void) const
450 {
451 return m_lastResult;
452 }
453
461 bool Terminate(DWORD result = 0)
462 {
463 BOOL r = ::TerminateThread(m_hThread, result);
464 _GetLastError("TerminateThread");
465 if ( r )
466 {
467 m_hThread = NULL;
468 }
469 return !! r;
470 }
471
478 void StopRequest(void)
479 {
480 if ( IsAlive() && m_pRunner->m_canRunnable )
481 {
482 #ifdef _DEBUG
483 if ( ! m_threadName.IsEmpty() )
484 {
485 TRACE3( TNB_THREADTRACETYPE, m_threadId, m_threadName.Ref(), _T("停止要求") );
486 }
487 #endif
488 //停止要求
489 ::ResumeThread(m_hThread);
490 SetPriority(THREAD_PRIORITY_NORMAL);
491 m_pRunner->m_canRunnable = false;
492 }
493 }
494
505 bool Stop(DWORD dwWait = 15000)
506 {
507 if ( m_threadId == ::GetCurrentThreadId() )
508 {
509 ASSERT0( false, "CThread::Stop()", "リスナースレッド処理内で Stop() は使用できません。" );
510 return false;
511 }
512 bool boRc = IsAlive();
513 if ( boRc && m_hThread != NULL )
514 {
515 DWORD dwExitCode;
516 if ( ! ::GetExitCodeThread(m_hThread, &dwExitCode) )
517 {
518 boRc = false;
519 }
520 else if ( dwExitCode != STILL_ACTIVE )
521 {
522 #ifdef _DEBUG
523 if ( ! m_threadName.IsEmpty() )
524 {
525 TRACE3( TNB_THREADTRACETYPE, m_threadId, m_threadName.Ref(), _T("既に停止...") );
526 }
527 #endif
528 boRc = false;
529 }
530 }
531 if ( boRc )
532 {
533 #ifdef _DEBUG
534 if ( ! m_threadName.IsEmpty() )
535 {
536 TRACE3( TNB_THREADTRACETYPE, m_threadId, m_threadName.Ref(), _T("停止要求") );
537 }
538 #if ( _WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400 )
539 if ( ::IsDebuggerPresent() )
540 {
541 dwWait = 0;
542 }
543 #endif
544 #endif
545 //停止要求
546 ::ResumeThread(m_hThread);
547 SetPriority(THREAD_PRIORITY_NORMAL);
548 m_pRunner->m_canRunnable = false;
549 //
550 if ( dwWait == 0 )
551 {
552 dwWait = DWORD_MAX;
553 }
554 else
555 {
556 dwWait /= 50;
557 }
558 //スレッド終了待ち
559 for ( DWORD i = 0; i < dwWait; i++ )
560 {
561 m_pRunner->m_canRunnable = false;
562 if ( m_hThread == NULL )
563 {
564 break;
565 }
566 DWORD dwExitCode;
567 if ( ::GetExitCodeThread(m_hThread, &dwExitCode) )
568 {
569 if ( dwExitCode != STILL_ACTIVE )
570 {
571 break;
572 }
573 }
574 if ( m_hOwnerWnd != NULL )
575 {
577 }
578 ::Sleep(50);
579 }
580 if ( m_hThread != NULL )
581 {
582 //終わらなかったらTerm....
583 if ( ! ::TerminateThread(m_hThread, 0) )
584 {
585 _GetLastError("TerminateThread");
586 }
587 TRACE0("ThreadをTerminateしました\n");
588 #ifdef _DEBUG
589 CWorkMemT<TCHAR> str(1024);
590 if ( ! m_threadName.IsEmpty() )
591 {
592 STRLIB::PrintF(str, 1024, _T("指定時間内に、") _T(TNB_THREADNAMEFRM2) _T("が終了しませんでした。\n 強制終了させました。")
593 ,m_threadId, m_threadName.Ref());
594 }
595 else
596 {
597 STRLIB::PrintF(str, 1024, _T("指定時間内に、") _T(TNB_THREADNAMEFRM1) _T("が終了しませんでした。\n 強制終了させました。")
598 ,m_threadId);
599 }
600 ASSERT1( false, "CThread::Stop()", "%s", str.Ref() );
601 #endif
602 }
603 }
604 if ( m_hThread != NULL )
605 {
606 il_CloseThreadHandle(m_hThread);
607 m_hThread = NULL;
608 }
609 return true;
610 }
611
618 bool Start(LPCTSTR lpszName = NULL)
619 {
620 if ( m_pRunner == NULL || IsAlive() )
621 {
622 return false;
623 }
624 #ifdef _DEBUG
625 m_threadName = lpszName;
626 #endif
627 //
628 m_hThread = il_CreateThread(ms_ThreadMain, this, &m_threadId);
629 if ( m_hThread == NULL )
630 {
631 // スレッド起動失敗
632 TRACE0( "スレッド起動失敗");
633 return false;
634 }
635 DWORD r = ::ResumeThread(m_hThread);
636 ASSERT( ToInt(r) != -1 );
638 m_pRunner->m_excThreadReady.Exchange(0/*ダミー*/);
639 return true;
640 }
641
647 void Suspend(void)
648 {
649 if ( m_pRunner != NULL )
650 {
651 m_pRunner->m_isOnDemandSuspend = true;
652 }
653 }
654
660 bool Resume(void)
661 {
662 int r = ToInt(::ResumeThread(m_hThread));
663 while ( r > 0 )
664 {
665 r = ToInt(::ResumeThread(m_hThread));
666 }
667 return r == 0;
668 }
669
675 static void PumpMessage(HWND hWnd)
676 {
677 MSG msg;
678 while ( ::PeekMessage(&msg, hWnd, 0, 0, PM_NOREMOVE) )
679 {
680 if ( ! ::GetMessage(&msg, hWnd, 0, 0) )
681 {
682 break;
683 }
684 bool r = (WM_KEYFIRST <= msg.message && msg.message <= WM_IME_KEYLAST);
685 r |= (WM_MOUSEFIRST <= msg.message && msg.message <= WM_MOUSELAST);
686 if ( r )
687 {
688 TRACE1("Drop Message = %d\n", msg.message);
689 }
690 else
691 {
692 ::TranslateMessage(&msg);
693 ::DispatchMessage(&msg);
694 }
695 }
696 }
697
698private:
699 IRunner* m_pRunner;
700 DWORD m_lastResult;
701 CSimpleStr m_threadName;
702
709 static DWORD WINAPI ms_ThreadMain(LPVOID lpPoint)
710 {
711 CThread* P = static_cast<CThread*>(lpPoint);
712 ASSERTLIB(P->m_threadId == ::GetCurrentThreadId());
713 P->m_pRunner->m_canRunnable = true;
714 P->m_pRunner->OnSetupThread();
715 P->m_pRunner->m_excThreadReady.Exchange(0/*ダミー*/);
716 #ifdef _DEBUG
717 if ( ! P->m_threadName.IsEmpty() )
718 {
719 TRACE3( TNB_THREADTRACETYPE, P->m_threadId, P->m_threadName.Ref(), _T("開始"));
720 }
721 #endif
722 P->m_lastResult = P->m_pRunner->Run();
723 #ifdef _DEBUG
724 if ( ! P->m_threadName.IsEmpty() )
725 {
726 TRACE3( TNB_THREADTRACETYPE, P->m_threadId, P->m_threadName.Ref(), _T("終了"));
727 }
728 #endif
729 P->m_pRunner->OnExitThread();
730 il_CloseThreadHandle(P->m_hThread);
731 P->m_hThread = NULL;
732 P->m_threadId = 0;
733 il_ExitThread(P->m_lastResult);
734 return P->m_lastResult;
735 }
736};
737
738
739
776{
777public:
778
789 struct IRunner
790 {
792 virtual ~IRunner(void) {}
798 virtual void Run(LPARAM lParam) = 0;
799 };
800
810 static bool Start(LPARAM lParam, IRunner* piRunner, bool withDelete = true, int priority = THREAD_PRIORITY_NORMAL)
811 {
812 CThreadlet* P = new CThreadlet;
813 P->m_pRunner = piRunner;
814 P->m_lParam = lParam;
815 P->m_withDelete = withDelete;
816 //
817 DWORD dwThreadId;
818 HANDLE hThread = il_CreateThread(ms_ThreadMain, P, &dwThreadId);
819 if ( hThread == NULL )
820 {
821 // スレッド起動失敗
822 TRACE0( "スレッド起動失敗");
823 if ( P->m_withDelete )
824 {
825 delete P->m_pRunner;
826 }
827 delete P;
828 return false;
829 }
830 ::SetThreadPriority(hThread, priority);
831 DWORD r = ::ResumeThread(hThread);
832 ASSERT(ToInt(r) != -1);
834 il_CloseThreadHandle(hThread);
835 P->m_excThreadReady.Exchange(0/*ダミー*/);
836 return true;
837 }
838
839private:
840
841 CExchangerT<BYTE> m_excThreadReady;
842 IRunner* m_pRunner;
843 bool m_withDelete;
844 LPARAM m_lParam;
851 static DWORD WINAPI ms_ThreadMain(LPVOID lpPoint)
852 {
853 CThreadlet* P = static_cast<CThreadlet*>(lpPoint);
854 P->m_excThreadReady.Exchange(0/*ダミー*/);
855 P->m_pRunner->Run(P->m_lParam);
856 ::Sleep(200);
857 if ( P->m_withDelete )
858 {
859 delete P->m_pRunner;
860 }
861 delete P;
862 il_ExitThread(0);
863 return 0;
864 }
865
867 CThreadlet(void) {}
868};
869
870
871
883{
884public:
885
892 CTemporarilyThreadPriority(int priority = THREAD_PRIORITY_TIME_CRITICAL)
893 : m_hThread(::GetCurrentThread())
894 {
895 m_Init(priority);
896 }
897
905 CTemporarilyThreadPriority(HANDLE hThread, int priority = THREAD_PRIORITY_TIME_CRITICAL)
906 : m_hThread(hThread)
907 {
908 m_Init(priority);
909 }
910
916 {
917 Restore();
918 }
919
924 void Restore(void)
925 {
926 if ( m_hThread != NULL )
927 {
928 ::SetThreadPriority(m_hThread, m_priority);
929 m_hThread = NULL;
930 }
931 }
932
933private:
934 void m_Init(int p)
935 {
936 m_priority = ::GetThreadPriority(m_hThread);
937 ::SetThreadPriority(m_hThread, p);
938 ASSERT( ::GetThreadPriority(m_hThread) == p );
939 }
940 HANDLE m_hThread;
941 int m_priority;
942};
943
944
945
946}; // TNB
947
948
949
スレッド間値入れ替え関係のヘッダ
文字列操作ライブラリ関係のヘッダ
[ETC] コピー不可能スーパークラス.
Definition: TnbDef.h:599
TYP Exchange(const TYP &t)
[取得] 値交換.
Definition: TnbExchanger.h:61
簡易文字列管理クラス.
Definition: TnbDef.h:772
bool IsEmpty(void) const
[確認] 空チェック
Definition: TnbDef.h:827
LPCTSTR Ref(void) const
[取得] 文字列参照
Definition: TnbDef.h:840
一時的スレッド優先度クラス
Definition: TnbThread.h:883
CTemporarilyThreadPriority(int priority=THREAD_PRIORITY_TIME_CRITICAL)
コンストラクタ.
Definition: TnbThread.h:892
void Restore(void)
[処理] リストア.
Definition: TnbThread.h:924
CTemporarilyThreadPriority(HANDLE hThread, int priority=THREAD_PRIORITY_TIME_CRITICAL)
コンストラクタ.
Definition: TnbThread.h:905
~CTemporarilyThreadPriority(void)
デストラクタ.
Definition: TnbThread.h:915
スレッド状態管理クラス
Definition: TnbThread.h:128
bool PostMessage(UINT message, WPARAM wParam=0, LPARAM lParam=0) const
[実行] PostThreadメッセージ
Definition: TnbThread.h:238
DWORD m_threadId
スレッドのID
Definition: TnbThread.h:268
HWND m_hOwnerWnd
オーナーウィンドウ
Definition: TnbThread.h:269
HANDLE GetHandle(void) const
[取得] スレッドのハンドル取得
Definition: TnbThread.h:154
void SetOwnerHwnd(HWND hWnd)
[設定] 関連ウィンドウハンドル設定.
Definition: TnbThread.h:188
CThreadStatus(void)
コンストラクタ.
Definition: TnbThread.h:132
bool IsAlive(void) const
[確認] スレッドが生きているか
Definition: TnbThread.h:177
DWORD GetId(void) const
[取得] スレッドのID取得
Definition: TnbThread.h:163
bool SetPriority(int priority=THREAD_PRIORITY_NORMAL)
[設定] 優先度設定
Definition: TnbThread.h:217
HANDLE m_hThread
スレッドのハンドル
Definition: TnbThread.h:267
DWORD_PTR SetAffinityMask(DWORD_PTR affinityMask)
[設定] プロセッサアフィニティマスク設定.
Definition: TnbThread.h:255
virtual ~CThreadStatus(void)
デストラクタ
Definition: TnbThread.h:137
int GetPriority(void) const
[取得] 優先度取得
Definition: TnbThread.h:206
スレッド管理クラス
Definition: TnbThread.h:316
bool Terminate(DWORD result=0)
[設定] スレッド中断
Definition: TnbThread.h:461
void Suspend(void)
[実行] サスペンド.
Definition: TnbThread.h:647
bool SetRunner(IRunner *pRunner)
[設定] ランナー、設定
Definition: TnbThread.h:420
bool Stop(DWORD dwWait=15000)
[設定] スレッド停止 スレッドに対して停止要求します。
Definition: TnbThread.h:505
bool Start(LPCTSTR lpszName=NULL)
[設定] スレッド開始
Definition: TnbThread.h:618
bool Resume(void)
[実行] レジューム.
Definition: TnbThread.h:660
DWORD GetThreadResult(void) const
[取得] スレッド終了値
Definition: TnbThread.h:449
CThread(void)
コンストラクタ
Definition: TnbThread.h:400
virtual ~CThread(void)
デストラクタ
Definition: TnbThread.h:408
void SetOwnerHwnd(HWND hOwner)
[設定] 関連ウィンドウハンドル設定.
Definition: TnbThread.h:439
static void PumpMessage(HWND hWnd)
[処理] メッセージポンプ.
Definition: TnbThread.h:675
void StopRequest(void)
[設定] スレッド停止要求.
Definition: TnbThread.h:478
簡易スレッド実行クラス
Definition: TnbThread.h:776
static bool Start(LPARAM lParam, IRunner *piRunner, bool withDelete=true, int priority=THREAD_PRIORITY_NORMAL)
[設定] スレッド開始
Definition: TnbThread.h:810
const TYP * Ref(void) const
[取得] ポインタ取得
Definition: TnbDef.h:712
int ToInt(LPCSTR lpsz, int iBase=10)
[変換] INT変換(ASCII/SJIS用).
Definition: TnbStrLib.h:367
void IgnoreUnusedValue(const T &value)
[宣言] 参照しない値宣言.
Definition: TnbDef.h:434
bool PrintF(LPSTR _pWork, size_t iLen, LPCSTR lpFmt,...)
[作成] 書式付き文字列作成(ASCII/SJIS用)
Definition: TnbDef.h:1101
TNB Library
Definition: TnbDoxyTitle.txt:2
スレッド実行管理ランナーインターフェース
Definition: TnbThread.h:341
virtual void OnExitThread(void)
[通知] スレッド終了通知.
Definition: TnbThread.h:386
IRunner(void)
コンストラクタ
Definition: TnbThread.h:346
bool IsRunnable(void) const
[確認] 実行可能か否か
Definition: TnbThread.h:355
virtual void OnSetupThread(void)
[通知] スレッド開始前通知.
Definition: TnbThread.h:380
virtual ~IRunner(void)
デストラクタ
Definition: TnbThread.h:343
virtual DWORD Run(void)=0
[動作] スレッド処理本体
簡易スレッド実行クラスのランナー
Definition: TnbThread.h:790
virtual void Run(LPARAM lParam)=0
[通知] スレッド処理部
virtual ~IRunner(void)
デストラクタ
Definition: TnbThread.h:792