Reusable background thread in MFC - c++

I want to create a reusable background thread to queue a number of tasks that require access to a singleton resource. The thread should be created at the start of the program and a message will be sent whenever it is required to complete a task. At first I was trying to use a worker thread, as the background thread doesn't have a UI, but then I noticed that only UI threads have message pumps. Unfortunately, PostThreadMessage always returns ERROR_INVALID_THREAD_ID, but I am sure the thread has been created correctly.
Is it a good choice to use a UI thread rather than a worker thread?
Why isn't my PostThreadMessage being received?
UPDATE: By looking at the output messages, I now know that the message isn't being received because the thread is killed
Sample code
DWORD deviceControllerThread;
void post(){
BOOL res=PostThreadMessage(deviceControllerthread,ControllerThread, ENROLLMENT_BEGIN, (WPARAM) myDataPointer, 0);
...
}
void MFC_Init(){
CWinThread* thread=AfxBeginThread(RUNTIME_CLASS(MFC_thread), THREAD_PRIORITY_NORMAL, 0, 0);
deviceControllerThread=thread->m_nThreadID;
}

When your thread initializes it just needs to call PeekMessage to "create" a message queue. Then the other thread can post messages to it via PostThreadMessage. Also, that error code of INVALID_THREAD_ID is a symptom that your worker thread has actually exited (or was never created). Make sure you have sufficient debug spew or logging to validate that the worker thread got created and didn't prematurely exit. Also, make sure you are checking the return code for AfxBeginThread and that m_nThreadID is valid (because I'm assume you initialized it to zero).
I do similar threading exercises all the time. I've moved away from using the message queue and onto using my own eventing and queues for finer control.
If you don't need to guarantee ordering of work items, then another idea is to just use the Windows "thread pool" to do the work for you.
Below is an OUTLINE of how I usually structure a thread class in C++. It's just something I whipped together based on existing projects and is NOT production code. But it should demonstrate some concepts of how to manage a thread lifetime.
// CList is any generic "array" or "list" class (you can use std::list, CAtlArray, CSimpleArray, etc...)
// ThreadMessage is your data structure for holding data to indicate to the thread what to do
// e.g.
// struct ThreadMessage
//{
// enum type; // YOUR_CODE_TO_QUIT=0, WORK_MESSAGE=1, etc...
// workdata data;
//};
class CMyThread
{
private:
CRITICAL_SECTION m_cs; // lock such that m_queue is thread safe, can be replaced with CComAutoCriticalSection or equivalent
bool m_fNeedToExit; // signals to the worker thread that it is time to exit
HANDLE m_hEvent; // For waking up the worker thread to tell it a new message is available
HANDLE m_hThread; // handle to worker thread
HANDLE m_hStartEvent; // For the worker thread to signal back to the parent thread that is has finished initializing
bool m_fStarted; // Has Start() been called
DWORD m_dwThread; // threadID
CList<ThreadMessage> m_queue; // generic "array" of work items. Can be replaced with any list-type data structure
public:
CMyThread()
{
InitializeCriticalSection(&m_cs);
}
~CMyThread()
{
Stop();
DeleteCriticalSection(&m_cs);
}
HRESULT Start()
{
if (m_fStarted)
return S_FALSE;
// todo - check all return codes from the Create functions!
m_hEvent = CreateEvent(0,0,0,0); // unsignalled, unnamed, auto-reset event
m_hStartEvent = CreateEvent(0,0,0,0); // unsignalled, unnamed, auto-reset event
m_hThread = CreateThread(NULL, 0, CMyThread::ThreadProc, this, 0, &m_dwThreadID);
// PUT YOUR THREAD INITIALIZATION CODE HERE
// wait for the thread to intialize (you don't have to call this next line if the thread doesn't have any initialization to wait for */
WaitForSingleObject(m_hStartEvent, INFINITE);
m_fStarted = true;
return S_OK;
}
HRESULT Stop()
{
if (m_hThread)
{
m_fNeedToExit = true;
ThreadMessage quitmessage;
quitmessage.type = YOUR_CODE_TO_QUIT;
SendMessageToThread(&quitmessage);
// in a debug build, you may want to wait for X seconds and show an error message if the worker thread appears hung
WaitForSingleObject(m_hThread, INFINITE);
// cleanup
CloseHandle(m_hThread); m_hThread = NULL;
CloseHandle(m_hStartEvent); m_hStartEvent = NULL;
CloseHandle(m_hEvent); m_hEvent= NULL;
m_fStarted = true;
m_dwThread = 0;
m_queue.empty();
}
return S_OK;
}
HRESULT SendMessageToThread(Message* pMsg)
{
if (m_fStarted == false)
return E_FAIL;
EnterCriticalSection(&m_cs);
m_queue.enque(*pMsg); //push message onto queue
LeaveCriticalSection(&m_cs);
SetEvent(m_hEvent); // signal the thread to wakeup and process it's message queue
return S_OK;
}
void ThreadProcImpl()
{
// initialize thread if needed (e.g. call PeekMessage to initialize the message queue if you need one - in this implementation you don't)
// signal back to the main thread we're off and running
SetEvent(m_hThreadStarted);
while (m_fNeedToExit == false)
{
bool fGotMsg = false;
ThreadMessage msg;
EnterCriticalSection(&m_cs);
if (m_queue.size > 0)
{
msg = m_queue.deque(); // remove the first message from the queue (if any)
fGotMsg = true;
}
LeaveCriticalSection(&m_cs);
// if the queue is empty, then wait for another message to come in
if (fGotMsg == false)
{
WaitForSingleObject(m_hEvent, INFINITE); // on return m_hEvent is auto-reset to unsignalled
continue; // back to top of while loop to deque
}
if (m_fNeedToExit) // check exit condition
break;
if (msg.type == YOUR_CODE_TO_QUIT)
break;
// YOUR CODE TO HANDLE "ThreadMessage msg" goes here. (i.e. "do the work")
}
// thread cleanup code goes here (if any)
}
static DWORD __stdcall ThreadProc(void* pcontext)
{
CMyThread* pThis = (CMyThread*)pcontext;
pThis->ThreadProcImpl();
return 0;
}
};

Related

QueueUserAPC function not working, reporting error 31 randomly

The following code uses the QueueUserAPC function to add commands to a dispatcher thread in order to synchronize console output.
#include <Windows.h>
#include <iostream>
constexpr auto fenceName = L"GlobalFence";
constexpr auto dispatchCloser = L"GlobalDispatchStop";
constexpr int threadCount = 5;
DWORD WINAPI pure(LPVOID lpThreadParameter)
{
const HANDLE dispatchCloseEvent = OpenEventW(EVENT_ALL_ACCESS, FALSE, dispatchCloser);
while(WaitForSingleObjectEx(dispatchCloseEvent, INFINITE, TRUE) != WAIT_IO_COMPLETION)continue;
return 0;
}
HANDLE dispatcher;
int main()
{
const HANDLE dispatchCloseEvent = CreateEventW(nullptr, TRUE, FALSE, dispatchCloser);
dispatcher = CreateThread(NULL, 1024, &pure, 0, 0, NULL);
const HANDLE g_FenceEvent = CreateEventW(nullptr, TRUE, FALSE, fenceName);
HANDLE threads[threadCount];
for (int i = 0; i < threadCount; i++)
{
threads[i] = CreateThread(NULL, 1024*1024,
[](LPVOID) -> DWORD
{
DWORD d = QueueUserAPC(([](ULONG_PTR) {std::cout << "thread opened\n"; }), dispatcher, NULL);
if(d == 0)std::cout << GetLastError() << std::endl;
HANDLE a = OpenEventW(EVENT_ALL_ACCESS, FALSE, fenceName);
WaitForSingleObject(a, INFINITE);
d = QueueUserAPC([](ULONG_PTR) {std::cout << "thread released\n"; }, dispatcher, NULL);
if (d == 0)std::cout << GetLastError() << std::endl;//often reports error 31
return 0;
},
0, 0, NULL);
}
Beep(300, 300);//the length of the delay effects the behavior, somehow.
SetEvent(g_FenceEvent);
SetEvent(dispatchCloseEvent);
WaitForMultipleObjects(threadCount, threads, TRUE, INFINITE);
WaitForSingleObject(dispatcher, INFINITE);
SetEvent(dispatchCloseEvent);
for (int i = 0; i < threadCount; i++)
CloseHandle(threads[i]);
CloseHandle(g_FenceEvent);
CloseHandle(dispatchCloseEvent);
}
The code executes correctly about 40% of the time. Sometimes (although this is somewhat rare) the "thread opened" text won't get written to the console the right amount of times, but no error is reported from getLastError()
As soon as the loop in pure() receives its 1st APC notification, the loop breaks and pure() exits, terminating the thread.
Error 31 is ERROR_GEN_FAILURE, and per the QueueUserAPC() documentation:
When the thread is in the process of being terminated, calling QueueUserAPC to add to the thread's APC queue will fail with (31) ERROR_GEN_FAILURE.
If you expect the dispatcher thread to process more than one APC notification, it needs to stay running. You meant to use == instead of != in your loop condition:
while (WaitForSingleObjectEx(dispatchCloseEvent, INFINITE, TRUE) == WAIT_IO_COMPLETION) continue;
That way, if the wait exits due to a queued APC, the loop will go back to waiting for the next APC. The loop will break, exiting pure() to terminate the thread, only when it receives a return value other than an APC notification, such as WAIT_OBJECT_0 when the close event is signaled.
Another problem I see is that you are signaling dispatchCloseEvent too soon, so the dispatcher thread can stop running while the fenced threads are still trying to queue APCs to it. That is why the 2nd call to QueueUserAPC() in each fenced thread fails randomly. You need to wait for all of the fenced threads to finish first, THEN signal the dispatcher to stop running.
SetEvent(g_FenceEvent);
WaitForMultipleObjects(threadCount, threads, TRUE, INFINITE);
SetEvent(dispatchCloseEvent); // <-- move here!
WaitForSingleObject(dispatcher, INFINITE);
Also, all of your threads are leaking the HANDLEs they open with OpenEventW(). You need to call CloseHandle() on them, per the OpenEventW() documentation:
Use the CloseHandle function to close the handle. The system closes the handle automatically when the process terminates. The event object is destroyed when its last handle has been closed.
For that matter, you don't really need OpenEventW() at all. You can pass the existing HANDLEs from main() to each thread via their LPVOID parameter instead:
DWORD WINAPI pure(LPVOID lpThreadParameter)
{
HANDLE dispatchCloseEvent = (HANDLE) lpThreadParameter;
...
return 0;
}
CreateThread(..., &pure, dispatchCloseEvent, ...);
CreateThread(...,
[](LPVOID param) -> DWORD
{
HANDLE a = (HANDLE) param;
...
},
g_fenceEvent, ...);
Or, just use global variables instead.
Either way, with OpenEventW() eliminated, there is no more need to assign names to your events when calling CreateEventW(), thus no longer exposing them to potential interference from outside code.
Also, you are also not closing the dispatcher thread's HANDLE either, like you are closing the fenced threads' HANDLEs.

Winapi Timer callback thread, never returns

I've got to debug some code which is not from me.
This code implement a timer API using winapi Timer interface.
I'm not very used to this Winapi functionality, so i could use your help :)
From what I understand this code is done like this :
=> Init()
timerQueue = CreateTimerQueue();
=> CreateTimer()
CreateTimerQueueTimer(timerHandle, timerQueue, timerCallback, ..., WT_EXECUTEDEFAULT);
=> timerCallback()
DeleteTimerQueueTimer(timerQueue , timerHandle, NULL));
calback() //Launch user-defined callback
=> CleanUp() // to be called at the end
DeleteTimerQueueEx(timerQueue , INVALID_HANDLE_VALUE);
When we test that, user-defined callback are executed successfully after the desired amount of time. But after that timerCallback threads keep pending and never return, preventing the all process to returns. Using VS debugger I can see those threads (named TppWorkerThread#4) on the thread...
Perhaps we miss something to make callback returns properly or we created some sort of deadlocks... However I cannot figure it out ...
Please let me know if I forgot some relevant information.
Thank you for your help.
EDIT:
Further information :
- Blocking thread are at this state at the end of the process :
* Category :Worker Thread
* Name : _TppWorkerThread#4
* Location : _ZwWaitForWorkViaWorkerFactory#8
* Priotity : Normal
EDIT2:
Having some more time to work on that strange behavior, I am now able to reproduce it in a standalone code.
#include <windows.h>
#include <stdio.h>
HANDLE gDoneEvent;
HANDLE hTimer[5];
HANDLE hTimerQueue = NULL;
HANDLE g_threadHandle;
void PeriodicCallback(void)
{
printf("Periodic routine called.\n");
}
void SingleCallback(void)
{
printf("Single routine called.\n");
if (!DeleteTimerQueueTimer(hTimerQueue, hTimer[2], NULL))
printf("DeleteTimerQueueTimer() fail. Return value is %d.\n", GetLastError());
}
void CALLBACK CommonCallback(PVOID lpParam, BOOLEAN TimerOrWaitFired)
{
printf("Common routine called. Parameter is %d.\n", *(int *)lpParam);
((void (*)(void))lpParam)();
}
void MainTest(void)
{
// Use an event object to track the TimerRoutine execution
gDoneEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (NULL == gDoneEvent)
{
printf("CreateEvent failed (%d)\n", GetLastError());
return -1;
}
if(0 == SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL))
{
printf("SetThreadPriority failed (%d)\n", GetLastError());
return -2;
}
// Create the timer queue.
hTimerQueue = CreateTimerQueue();
if (NULL == hTimerQueue)
{
printf("CreateTimerQueue failed (%d)\n", GetLastError());
return -3;
}
/*
if (!CreateTimerQueueTimer( &hTimer[2], hTimerQueue,
(WAITORTIMERCALLBACK)CommonCallback, &SingleCallback, 1000, 0, WT_EXECUTEDEFAULT))
{
printf("CreateTimerQueueTimer failed (%d)\n", GetLastError());
return -4;
}
*/
if (!CreateTimerQueueTimer( &hTimer[4], hTimerQueue,
(WAITORTIMERCALLBACK)CommonCallback, &PeriodicCallback, 10, 500, WT_EXECUTEDEFAULT))
{
printf("CreateTimerQueueTimer failed (%d)\n", GetLastError());
return -5;
}
// TODO: Do other useful work here
printf("Call timer routine in 10 seconds...\n");
Sleep(4000);
CloseHandle(gDoneEvent);
if (!DeleteTimerQueueTimer(hTimerQueue, hTimer[4], INVALID_HANDLE_VALUE))
printf("DeleteTimerQueueTimer failed (%d)\n", GetLastError());
// Delete all timers in the timer queue.
if (!DeleteTimerQueueEx(hTimerQueue, INVALID_HANDLE_VALUE))
printf("DeleteTimerQueue failed (%d)\n", GetLastError());
Sleep(1000);
ExitThread(0);
}
int main(int argc, char **argv[])
{
if(g_threadHandle == CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MainTest, NULL, 0, NULL))
printf("Creation fail");
ExitThread(0);
}
I'm compiling this code on VisualStudio 2010 Professional.
It appears that event after calling DeleteTimerQueueTimer() some threads remain pending on the threads pool, preventing my process to shutdown. I still cannot figured it out ...
When you call DeleteTimerQueueEx with an INVALID_HANDLE_VALUE as its second parameter it will block until all callbacks which are running have completed. The Error may be in one of your callback functions which never returns.
You are calling DeleteTimerQueueTimer(timerQueue , timerHandle, NULL); with NULL as the third parameter, this will not wait for the callback to complete if one is running at the time you delete the timer. I suggest using DeleteTimerQueueTimer(timerQueue , timerHandle, INVALID_HANDLE_VALUE) which will block until the call back completes (if one is running). Calling cleanUp() without using the blocking version of DeleteTimerQueueTimer is likely a bug as you may be cleaning up at the same time as the callback is executing.
It could also be a problem of calling DeleteTimerQueueEx or DeleteTimerQueueTimer from within a callback, which is forbidden. Break on execution of DeleteTimerQueueEx and look at what thread you are in, if its a TppWorkerThread than you have found your bug.
EDIT:
In your comment you say you do call DeleteTimerQueueTimer from within the callback but don't use INVALID_HANDLE_VALUE, reading the documentation again from http://msdn.microsoft.com/en-us/library/windows/desktop/ms682569%28v=vs.85%29.aspx this does seem to be legal but I distinctly remember us making design decisions to avoid this, I'm sorry this is so vague, I hope someone can give authoritative advice on this.
We send an event/message to the queue of a non timer thread which then removes the timer, you could even have a dedicated thread for this but that is probably overkill. At the end of the day you need to be sure that the timer is removed before doing cleanup so you have to either block on removal or have some other thread do it upon signaling of an event.
After some work on that issue I think I got to an answer.
I appears that this timerQueue API is coded on top of threadPool winAPI, and when we ask to create a timerQueue Windows create a thread pool from where all callback will be launched.
Until here no problem, but, when we ask for timerQueue deletion, it appears that this thread pool is not deleted...
This result in some thread keeping pending waiting to be used and preventing the process to returns.
After some time (timeout??) those threads returns and the process exit.
I don't really get why this pool is not closed... but, now, I use a workaround :
exit(0);
At the end of my program, it's a bit brutal but it does the job (ie: killing my process, whatever threads are still pending or not)

Placing calling thread in an alertable wait state

My main thread creates multiple I/O worker threads. I then initiate an I/O request from my main thread by doing:
{
...
IoRequest *pIoRequest = new IoRequest(m_socket);
pIoRequest->SetBuffer(vecCommandData); // vector of BYTEs
pIoRequest->SetOperationType(OP_TYPE_SEND);
WSASend(m_socket, pIoRequest->GetWsaBuffer(), 1, NULL, 0, pIoRequest, NULL);
...
}
At some point in one of my I/O worker threads, the request is completed and my IoRequest object's buffer is filled with valid response data.
DWORD WINAPI WorkerThreadProc(LPVOID lpParameter)
{
IoCompletionPort *pIocp = reinterpret_cast<IoCompletionPort*>(lpParameter);
...
while (true)
{
BOOL bReturn = pIocp->GetStatus(&ulCompletionKey, &dwNumberOfBytesTransferred, (LPOVERLAPPED*)&pIoRequest);
...
switch (pIoRequest->GetOperationType())
{
...
case OP_TYPE_RECEIVE_DATA:
{
...
// the requested I/O operation has completed and pIoRequest's buffer now contains valid response data!
break;
}
...
}
}
return 0;
}
How can I place my main thread in an alertable wait state after calling WSASend() and make it receive the response data whenever it's ready?
In an IOCP server, it's typically GetQueuedCompletionStatus().

How can I get which object timed out when using WaitForMultipleObjects?

If I'm using WaitForMultipleObjects, and the function returns WAIT_TIMEOUT, how can I get which object or objects caused the timeout to occur?
Another question I have is if multiple objects are signaled, since the return value only returns the first object that it detects as signaled, how do I get the other objects which are signaled?
#include <windows.h>
#include <stdio.h>
HANDLE ghEvents[2];
DWORD WINAPI ThreadProc( LPVOID );
int main( void )
{
HANDLE hThread;
DWORD i, dwEvent, dwThreadID;
// Create two event objects
for (i = 0; i < 2; i++)
{
ghEvents[i] = CreateEvent(
NULL, // default security attributes
FALSE, // auto-reset event object
FALSE, // initial state is nonsignaled
NULL); // unnamed object
if (ghEvents[i] == NULL)
{
printf("CreateEvent error: %d\n", GetLastError() );
ExitProcess(0);
}
}
// Create a thread
hThread = CreateThread(
NULL, // default security attributes
0, // default stack size
(LPTHREAD_START_ROUTINE) ThreadProc,
NULL, // no thread function arguments
0, // default creation flags
&dwThreadID); // receive thread identifier
if( hThread == NULL )
{
printf("CreateThread error: %d\n", GetLastError());
return 1;
}
// Wait for the thread to signal one of the event objects
dwEvent = WaitForMultipleObjects(
2, // number of objects in array
ghEvents, // array of objects
FALSE, // wait for any object
5000); // five-second wait
// The return value indicates which event is signaled
switch (dwEvent)
{
// ghEvents[0] was signaled
case WAIT_OBJECT_0 + 0:
// TODO: Perform tasks required by this event
printf("First event was signaled.\n");
break;
// ghEvents[1] was signaled
case WAIT_OBJECT_0 + 1:
// TODO: Perform tasks required by this event
printf("Second event was signaled.\n");
break;
case WAIT_TIMEOUT:
// How can I get which object timed out?
printf("Wait timed out.\n");
break;
// Return value is invalid.
default:
printf("Wait error: %d\n", GetLastError());
ExitProcess(0);
}
// Close event handles
for (i = 0; i < 2; i++)
CloseHandle(ghEvents[i]);
return 0;
}
DWORD WINAPI ThreadProc( LPVOID lpParam )
{
// lpParam not used in this example
UNREFERENCED_PARAMETER( lpParam);
// Set one event to the signaled state
if ( !SetEvent(ghEvents[0]) )
{
printf("SetEvent failed (%d)\n", GetLastError());
return 1;
}
return 0;
}
When the WaitForMultipleObjects(...) returns with the WAIT_TIMEOUT return code, it indicates that none of your you objects you waited for signaled within the given amount of time.
The function essentially sleeps for the time you specify as timeout and only returns earlier, if one of the waitable objects gets signaled before that time. That means that the WAIT_TIMEOUT return code is not associated with any of the objects you wait for.
Your second question is partialy answered by Eregriths comment. To check if other objects are also signaled, you could call WaitForMultipleObjects(...) again, and depending on your needs, set the timeout value to 0 (do not wait). When WaitForMultipleObjects(...) returns with WAIT_TIMEOUT you know that no other objects were in a signaled state at the time of your call, but you should keep in mind, that the object, that caused your first call to return could potentially be signaled again. So you could either exclude it from your array or simply check a single object for its state with the WaitForSingleObject(...) function.
If you want to make sure all objects are signaled, you can also play with the bWaitAll parameter. WaitForMultipleObjects(...) will then only return if all your objects are in a signaled state.,
Hope that helps a bit.

Safely synchronizing a COM thread

I've done a lot with multithreading in the past, but I'm fairly new to COM. Anyway, here's my issue:
I create a worker thread, which registers as an STA, and creates a COM object. Then the worker thread and the main thread try to communicate with each other. Using CoMarshalInterThreadInterfaceInStream and CoGetInterfaceAndReleaseStream, I can get the threads to call methods on the COM objects in the other thread.
Here's what the worker thread looks like:
void workerThread()
{
CoInitialize(NULL);
MyLib::IFooPtr foo = ...; // create my COM object
// Marshall it so the main thread can talk to it
HRESULT hr = CoMarshalInterThreadInterfaceInStream(foo.GetIID(),
foo.GetInterfacePtr(),
&m_stream);
if (FAILED(hr)) {
// handle failure
}
// begin message loop, to keep this STA alive
MSG msg;
BOOL bRet;
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1) break;
DispatchMessage(&msg);
}
}
In the main thread:
// launch the thread
m_worker = boost::thread (&workerThread);
// get the interface proxy
MyLib::IFooPtr foo;
LPVOID vp (NULL);
HRESULT hr = CoGetInterfaceAndReleaseStream(m_stream, foo.GetIID(), &vp);
if (SUCCEEDED(hr)) foo.Attach(static_cast<MyLib::IFoo*>(vp));
This creates the object (which takes a while to initialize), and allows the main thread to talk to it, and everything is properly synchronized with the COM Apartment stuff. As far as I can tell from reading msdn, this seems to be the right way to do things. Now the main thread can use its proxy to call methods on my COM object, and the worker thread will receive those calls over the message queue, properly dispatching them.
However, what about synchronizing these threads?
Obviously in this case I want the main thread to wait to call CoGetInterfaceAndReleaseStream until after the worker thread has created that stream via CoMarshalInterThreadInterfaceInStream. But how can I safely do that?
From MSDN, I should be using something like MsgWaitForMultipleObjects, so I can wait for my_condition OR new_message_arrived, and then I can do something like:
// verbatim from msdn
while (TRUE)
{
// wait for the event and for messages
DWORD dwReturn = ::MsgWaitForMultipleObjects(1,
&m_hDoneLoading, FALSE, INFINITE, QS_ALLINPUT);
// this thread has been reawakened. Determine why
// and handle appropriately.
if (dwReturn == WAIT_OBJECT_0)
// our event happened.
break ;
else if (dwReturn == WAIT_OBJECT_0 + 1)
{
// handle windows messages to maintain
// client liveness
MSG msg ;
while(::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
::DispatchMessage(&msg) ;
}
}
But how do I mix boost::thread.join() and boost::condition.wait() with MsgWaitForMultipleObjects? Is that even possible, or do I have to do something else to avoid a race condition?
Your main thread has a message queue (must be, since is an STA host), why not simply post a message to it, PostThreadMessage? Post an user message (WM_USER +X) and your normal main thread message pump can handle this user message as a notification that the COM object has marshaled the interface into the stream and the main thread is safe to call CoGetInterfaceAndReleaseStream.
I must call out though that with your current design your worker thread does basically nothing more than just run an additional message pump. Any call to any method on your interface from the main thread will block, wait for the worker thread to pick up the message from its message queue, process the call, respond, and then the main thread will resume. All operations will be at least as slow as having the COM object hosted in the main thread, plus the overhead of COM marshaling back and forth between the two STAs. Basically there is no concurrency whatsoever between the two threads, because of how COM STA works. Are you sure is this what you want?
Edit
(omitting a bunch of details like number of threads, timeout handling, assignment of a stream/IID/CLSID for each worker etc etc)
in the .h:
HANDLE m_startupDone;
volatile int m_threadStartCount;
worker thread:
void workerThread()
{
CoInitialize(NULL);
MyLib::IFooPtr foo = ...; // create my COM object
// Marshall it so the main thread can talk to it
HRESULT hr = CoMarshalInterThreadInterfaceInStream(foo.GetIID(),
foo.GetInterfacePtr(),
&m_stream);
if (FAILED(hr)) {
// handle failure
// remember to decrement and signal *even on failure*
}
if (0 == InterlockedDecrement(&m_threadStartCount))
{
SetEvent (m_startupDone);
}
// begin message loop, to keep this STA alive
MSG msg;
BOOL bRet;
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1) break;
DispatchMessage(&msg);
}
}
in the main thread:
m_startupDone = CreateEvent (NULL, FALSE, FALSE, NULL);
m_threadStartCount = <number of workerthreads>
// launch the thread(s)
m_worker = boost::thread (&workerThread);
m_worker2 = boost::thread (&workerThread);
...
// now wait for tall the threads to create the COM object(s)
if (WAIT_OBJECT0 != WaitForSingleObject(m_startupDone, ...))
{
// handle failure like timeout
}
// By now all COM objects are guaranteed created and marshaled, unmarshall them all in main
// here must check if all threads actually succeeded (could be as simple as m_stream is not NULL)
// get the interface proxy
MyLib::IFooPtr foo;
LPVOID vp (NULL);
HRESULT hr = CoGetInterfaceAndReleaseStream(m_stream, foo.GetIID(), &vp);
if (SUCCEEDED(hr)) foo.Attach(static_cast<MyLib::IFoo*>(vp));