I'm trying to get APC to work in my C++ code but I fail. I'm lost for words. In C# it works all fine (logically the same code). I want thread 2 to inject a call into thread 1. But in my C++ project it wont execute for some reason. What am I doing wrong ?
thread 1 (main thread)
thread 2 (sub thread, that needs the main thread to execute a function)
Code:
#include "stdio.h"
#include "windows.h"
#define TIME 2500
#define LAST_ERROR printf("last error: %i\r\n", GetLastError());
HANDLE handle1, handle2;
void ThreadInfo(char* prefix = "")
{
printf("%sthread id: %i\r\n", prefix, GetCurrentThreadId());
}
VOID CALLBACK apc( _In_ ULONG_PTR data)
{
ThreadInfo(" -> apc: 2 -> 1: ");
}
void run1()
{
while (true)
{
Sleep(TIME);
ThreadInfo("1: ");
// apc
//QueueUserAPC(apc, handle2, (ULONG_PTR) NULL);
}
}
void run2()
{
while (true)
{
Sleep(TIME);
ThreadInfo("2: ");
// apc
QueueUserAPC(apc, handle1, (ULONG_PTR) NULL);
}
}
void TestThreads()
{
DWORD threadId;
SECURITY_ATTRIBUTES a;
a.nLength = 12;
a.lpSecurityDescriptor = NULL;
a.bInheritHandle = 1;
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &handle1, 0, true, 2);
LAST_ERROR
handle2 = CreateThread(NULL, 100000, (LPTHREAD_START_ROUTINE)run2, NULL, 0, &threadId);
printf("handles (1, 2): %i, %i\r\n", handle1, handle2);
printf("ids (1, 2): %i, %i\r\n", threadId, GetCurrentThreadId());
printf("--------------------------------\r\n");
run1();
}
int main()
{
TestThreads();
printf("done.");
getchar();
return 0;
}
Sleep(TIME);
That's your problem statement. APCs are pretty dangerous, they permit code re-entrancy. The rough equivalent to the infamous Application.DoEvents() statement that got so many VB programmers in trouble. Windows doesn't just let them run, you have to be explicit that your code is re-entrant so that the APC can safely run without screwing up your program state.
The specific requirement is that your thread is in an "alertable wait state". Getting into a wait state is not the issue, the Sleep() call does that. It is however not an alertable state. You have to use this instead:
SleepEx(TIME, TRUE);
Modify the run1() function in your test program and you'll now see the APC callback getting called. Compare to GetOverlappedResultEx(), SignalObjectAndWait(), WaitForSingleObjectEx() and WaitForMultipleObjectsEx(), other winapi calls that can put a thread in an alertable wait state. And yes, Thread.Sleep() in a managed program is alertable, the CLR calls SleepEx() under the hood.
Related
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.
I am programming in Visual Studio 2008 in console application. I am working with a display that is communicated by Rs 232.
I have a thread that counts from 0 to 10 seconds. When reaches 10 I want to turn off the displays backlight. For that I have a function that is called from the thread. The called from the thread is well because I know that the code of the function is executed.
But code of turning the backlight off does not work when the function is called from the thread and it works the it is called from another place. Any ideas?
Thanks.
void FunctionBacklightoff(HANDLE portHandle,DWORD bytesTransmitted)
{
cout << "backoff";
WriteFile(portHandle, backlight_off , 4, &bytesTransmitted, NULL);//does not work when
//it is called from the thread. It works when it is called from wmain()
}
DWORD WINAPI solo_thread(void* arg)
{
int Counter = 0;
printf( "In second thread...\n" );
while ( true )
{
if(Counter<10)
{
Counter++;
Sleep(1000);
}
else
{
printf( "Han pasado 10 segundos; Counter:-> %d\n", Counter );
FunctionBacklightoff(portHandle,bytesTransmitted);//from here doesnt work
Counter = 0;
}
}
return 0;
}
int wmain(void)
{
hThread =CreateThread(NULL, 0, solo_thread,NULL ,0, NULL);
//inicialize rs232 communications...
retVal = PortOpen(&portHandle, 115200);
if (!retVal)
{
printf("Could not open CoM port");
getchar();
}
else
{
printf("CoM port opened successfully");
retVal = FALSE;
}
FunctionBacklightoff(portHandle,bytesTransmitted);//from here works
}
How portHandle is declared? Looks like it's static field so thread could simply not get change that happen after it's creation. To be sure you could mark portHandle as volatile or change the order of operations:
//Open port so we will be sure that postHandle is populated before thread starts.
retVal = PortOpen(&portHandle, 115200);
hThread = CreateThread(NULL, 0, solo_thread,NULL ,0, NULL);
Also you have a BUG that your wmain will exit before thread being executed. To fix that you should place following code right before wmain last bracket:
WaitForSingleObject(hThread, INFINITE);
Note that because your thread have while(true) without break condition it will run forever and each 10 seconds will switch off backlight. If this was not intentional add a break into else.
I'm using the following code from Microsoft as a template:
#include <windows.h>
#include <stdio.h>
#define MAX_SEM_COUNT 10
#define THREADCOUNT 12
HANDLE ghSemaphore;
DWORD WINAPI ThreadProc( LPVOID );
int main( void )
{
HANDLE aThread[THREADCOUNT];
DWORD ThreadID;
int i;
// Create a semaphore with initial and max counts of MAX_SEM_COUNT
ghSemaphore = CreateSemaphore(
NULL, // default security attributes
MAX_SEM_COUNT, // initial count
MAX_SEM_COUNT, // maximum count
NULL); // unnamed semaphore
if (ghSemaphore == NULL)
{
printf("CreateSemaphore error: %d\n", GetLastError());
return 1;
}
// Create worker threads
for( i=0; i < THREADCOUNT; i++ )
{
aThread[i] = CreateThread(
NULL, // default security attributes
0, // default stack size
(LPTHREAD_START_ROUTINE) ThreadProc,
NULL, // no thread function arguments
0, // default creation flags
&ThreadID); // receive thread identifier
if( aThread[i] == NULL )
{
printf("CreateThread error: %d\n", GetLastError());
return 1;
}
}
// Wait for all threads to terminate
WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);
// Close thread and semaphore handles
for( i=0; i < THREADCOUNT; i++ )
CloseHandle(aThread[i]);
CloseHandle(ghSemaphore);
return 0;
}
DWORD WINAPI ThreadProc( LPVOID lpParam )
{
// lpParam not used in this example
UNREFERENCED_PARAMETER(lpParam);
DWORD dwWaitResult;
BOOL bContinue=TRUE;
while(bContinue)
{
// Try to enter the semaphore gate.
dwWaitResult = WaitForSingleObject(
ghSemaphore, // handle to semaphore
0L); // zero-second time-out interval
switch (dwWaitResult)
{
// The semaphore object was signaled.
case WAIT_OBJECT_0:
// TODO: Perform task
printf("Thread %d: wait succeeded\n", GetCurrentThreadId());
bContinue=FALSE;
// Simulate thread spending time on task
Sleep(5);
// Release the semaphore when task is finished
if (!ReleaseSemaphore(
ghSemaphore, // handle to semaphore
1, // increase count by one
NULL) ) // not interested in previous count
{
printf("ReleaseSemaphore error: %d\n", GetLastError());
}
break;
// The semaphore was nonsignaled, so a time-out occurred.
case WAIT_TIMEOUT:
printf("Thread %d: wait timed out\n", GetCurrentThreadId());
break;
}
}
return TRUE;
}
And I want to adapt it so instead of being the threads the ones that determine how the semaphore fills, it's done by processes, meaning that the semaphore will fill if there are processes running and/or with any of their habdles not closes, and indeed I sort of have done it by changing the working of the thread function with this new function.
DWORD WINAPI ThreadProc( LPVOID lpParam )
{
// lpParam not used in this example
UNREFERENCED_PARAMETER(lpParam);
DWORD dwWaitResult;
BOOL bContinue=TRUE;
STARTUPINFO si;
PROCESS_INFORMATION pi;
memset(&si,0,sizeof(si));
si.cb=sizeof(si);
while(bContinue)
{
// Try to enter the semaphore gate.
dwWaitResult = WaitForSingleObject(
ghSemaphore, // handle to semaphore
0L); // zero-second time-out interval
CreateProcess("arbol.exe",NULL,NULL,NULL,0,0,NULL,NULL,&si,&pi);
WaitForSingleObject(pi.hProcess,INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
switch (dwWaitResult)
{
// The semaphore object was signaled.
case WAIT_OBJECT_0:
// TODO: Perform task
printf("Thread %d: wait succeeded\n", GetCurrentThreadId());
bContinue=FALSE;
// Simulate thread spending time on task
Sleep(5);
// Release the semaphore when task is finished
if (!ReleaseSemaphore(
ghSemaphore, // handle to semaphore
1, // increase count by one
NULL) ) // not interested in previous count
{
printf("ReleaseSemaphore error: %d\n", GetLastError());
}
break;
// The semaphore was nonsignaled, so a time-out occurred.
case WAIT_TIMEOUT:
printf("Thread %d: wait timed out\n", GetCurrentThreadId());
break;
}
}
return TRUE;
}
With that, although what determines the filling of the semaphore is the thread, in a practical sense it is determined by the complete execution and closing of the handles of the process.
But this looks as a lame way to solve this problem and I bet doing it this way is likely to give problems in the future if extra things are needed from those processes.
How can I create a semaphore so what would really determine the filling of the semaphore would be the processes? To clarify, this would be one possible solution that I don't think it is possible anyhow.
Let's consider that you could Create a Process by something like this:
aThread[i] = CreateProcess(
NULL, // default security attributes
0, // default stack size
(LPTHREAD_START_ROUTINE) ThreadProc,
NULL, // no thread function arguments
0, // default creation flags
&ThreadID); // receive thread identifier
Then LPTHREAD_START_ROUTINE would be equivalent in its working but for processes.
Semaphores are supposed to support Interprocess Synchronization in Windows API, but I cannot find any example that specifically uses processes, and I don't get the idea of how could it be done.
Any idea on how to achieve what I want?
Regards.
You want a named semaphore. Where each process shares the semaphore by creating it with the same name.
Create a named semaphore. Same as you have before, but that last parameter gets a string passed to it:
HANDLE hSemaphore = CreateSemaphore(NULL,
MAX_SEM_COUNT,
MAX_SEM_COUNT,
L"TheSemaphoreForMyApp");
Child processes, upon being started, can attach to that same semaphore and get a handle to it by using OpenSemaphore.
HANDLE hSemaphore = OpenSemaphore(EVENT_ALL_ACCESS,
FALSE,
L"TheSemaphoreForMyApp");
You don't have to hardcode a string as the semaphore name. The parent process can create a unique name each time, and then passes that name (e.g. command line parameter) to the child process. That will allow for multiple instances of your program with child processes to cooperate.
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)
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));