Last active
January 15, 2021 01:28
-
-
Save udaken/55cc7b89aa65a9a34917d4ef21f49967 to your computer and use it in GitHub Desktop.
Exsample using PostThreadMessage() and GetMessage() without boost
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #pragma once | |
| #include <windows.h> | |
| #include <assert.h> | |
| #ifdef _WIN32_WCE | |
| #define _beginthreadex(security, \ | |
| stack_size, \ | |
| start_proc, \ | |
| arg, \ | |
| flags, \ | |
| pid) \ | |
| CreateThread(security, \ | |
| stack_size, \ | |
| (LPTHREAD_START_ROUTINE) start_proc, \ | |
| arg, \ | |
| flags, \ | |
| (LPDWORD) pid) | |
| #else _WIN32_WCE | |
| #include <process.h> | |
| #endif _WIN32_WCE | |
| template <class ITaskCallback> | |
| class Task | |
| { | |
| public: | |
| Task() | |
| : m_hThread(NULL), m_hStartCompleted(NULL), m_dwThreadId(0), m_dwExitCode(STILL_ACTIVE) | |
| { | |
| } | |
| bool Start() | |
| { | |
| m_hStartCompleted = ::CreateEvent(NULL, FALSE, FALSE, NULL); | |
| m_hThread = (HANDLE)_beginthreadex(NULL, 0, &threadproc, this, 0, &m_dwThreadId); | |
| if (m_hThread) | |
| { | |
| ::WaitForSingleObject(m_hStartCompleted, INFINITE); | |
| ::CloseHandle(m_hStartCompleted); | |
| } | |
| return true; | |
| } | |
| ~Task() | |
| { | |
| assert("Must call Join() or Detach()" && m_hThread == NULL /* Must call Join() or Detach()*/); | |
| Join(); | |
| ::CloseHandle(m_hThread); | |
| } | |
| BOOL NotifyQuiet() | |
| { | |
| return PostMessage(WM_QUIT, 0, 0); | |
| } | |
| HANDLE Detach() | |
| { | |
| return std::exchange(m_hThread, NULL); | |
| } | |
| bool Enqueue(ITaskCallback &item) | |
| { | |
| return PostMessage(WM_ENQUEUEITEM, reinterpret_cast<WPARAM>(&item)); | |
| } | |
| bool Join() | |
| { | |
| if (m_hThread) | |
| { | |
| ::WaitForSingleObject(m_hThread, INFINITE); | |
| ::GetExitCodeThread(m_hThread, &m_dwExitCode); | |
| ::CloseHandle(m_hThread); | |
| m_hThread = NULL; | |
| return true; | |
| } | |
| return false; | |
| } | |
| DWORD GetThreadId() const | |
| { | |
| return m_dwThreadId; | |
| } | |
| DWORD GetExitCode() const | |
| { | |
| return m_dwExitCode; | |
| } | |
| bool Terminate(DWORD dwexitCode = 0) | |
| { | |
| if (m_hThread) | |
| { | |
| BOOL fResult = ::TerminateThread(m_hThread, dwexitCode); | |
| if (fResult) | |
| { | |
| m_dwExitCode = dwexitCode; | |
| ::CloseHandle(m_hThread); | |
| m_hThread = NULL; | |
| return true; | |
| } | |
| return false; | |
| } | |
| } | |
| private: | |
| enum { WM_ENQUEUEITEM = WM_APP }; | |
| BOOL PostMessage(UINT uiMsg, WPARAM wParam = 0, LPARAM lParam = 0) | |
| { | |
| return ::PostThreadMessage(m_dwThreadId, uiMsg, wParam, lParam); | |
| } | |
| HANDLE m_hThread; | |
| unsigned int m_dwThreadId; | |
| HANDLE m_hStartCompleted; | |
| DWORD m_dwExitCode; | |
| static unsigned __stdcall threadproc(void *vpArguments) | |
| { | |
| Task *self = static_cast<Task *>(vpArguments); | |
| // メッセージキューの作成 | |
| MSG msg = {}; | |
| (void)::PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); | |
| ::SetEvent(self->m_hStartCompleted); | |
| while (::GetMessage(&msg, NULL, 0, 0) != 0) | |
| { | |
| switch (msg.message) | |
| { | |
| case WM_NULL: | |
| Sleep(rand()); | |
| break; | |
| case WM_ENQUEUEITEM: | |
| { | |
| ITaskCallback *item = reinterpret_cast<ITaskCallback*>(msg.wParam); | |
| (*item)(); | |
| } | |
| break; | |
| } | |
| } | |
| return 0; | |
| } | |
| }; | |
| template <class TArg, class TResult> | |
| class TaskDelegate | |
| { | |
| friend class Task<typename TaskDelegate>; | |
| public: | |
| explicit TaskDelegate(const TArg &arg) | |
| : hCompleteEvent(::CreateEvent(NULL, FALSE, FALSE, NULL)), | |
| m_arg(arg) | |
| { | |
| assert(hCompleteEvent != NULL); | |
| } | |
| virtual ~TaskDelegate() | |
| { | |
| if (hCompleteEvent) | |
| ::CloseHandle(hCompleteEvent); | |
| } | |
| const TResult& GetResult() const | |
| { | |
| return m_result; | |
| } | |
| DWORD WaitForComplete(DWORD dwTimeout = INFINITE) | |
| { | |
| return ::WaitForSingleObject(hCompleteEvent, dwTimeout); | |
| } | |
| void operator() () | |
| { | |
| m_result = Callback(m_arg); | |
| ::SetEvent(hCompleteEvent); | |
| } | |
| protected: | |
| virtual TResult Callback(TArg arg) = 0; | |
| private: | |
| TArg m_arg; | |
| TResult m_result; | |
| HANDLE hCompleteEvent; | |
| }; | |
| class Callback1 : public TaskDelegate<int, int> | |
| { | |
| public: | |
| explicit Callback1(int i): TaskDelegate(i){}; | |
| virtual int Callback(int arg) { | |
| return printf("%u: %d\n", GetCurrentThreadId(), arg); | |
| }; | |
| }; | |
| int main() | |
| { | |
| Task<Callback1> t; | |
| t.Start(); | |
| Callback1 item1(1); | |
| Callback1 item2(2); | |
| Callback1 item3(3); | |
| Callback1 item4(4); | |
| Callback1 item5(5); | |
| t.Enqueue(item1); | |
| t.Enqueue(item2); | |
| t.Enqueue(item3); | |
| t.Enqueue(item4); | |
| item4.WaitForComplete(); | |
| t.Enqueue(item5); | |
| item5.WaitForComplete(); | |
| t.NotifyQuiet(); | |
| t.Join(); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment