Skip to content

Instantly share code, notes, and snippets.

@udaken
Last active January 15, 2021 01:28
Show Gist options
  • Save udaken/55cc7b89aa65a9a34917d4ef21f49967 to your computer and use it in GitHub Desktop.
Save udaken/55cc7b89aa65a9a34917d4ef21f49967 to your computer and use it in GitHub Desktop.
Exsample using PostThreadMessage() and GetMessage() without boost
#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