I have the problem that a thread that was sent to sleep using SleepEx(INFINITE, true) does not reliably continue when an APC is queued.
The application scenario is that software A must notice when software B has installed a certain Windows service.
For this, I create a new thread, register a callback function via NotifyServiceStatusChange(), and put the thread to sleep via SleepEx(INFINITE, true).
If, during the runtime of software A, the specified service is installed, the callback function is called, the thread is continued, and finishes its run() method. Everything works fine.
But, if software A terminates without the callback function being called, I still want the thread to terminate properly.
The Microsoft documentation states this about the SleepEx function:
Execution resumes when one of the following occurs:
An I/O completion callback function is called.
An asynchronous procedure call (APC) is queued to the thread.
The time-out interval elapses.
Therefore, I queue an APC to my thread using QueueUserAPC(). This works fine, my function stopSleeping() is called and executed: A breakpoint can be reached and debug output can be made inside this function.
Unfortunately, contrary to my expectation, my own APC does not cause the thread to resume running, as the call of the function callback() does.
The question is, why not?
My thread is a class derived from QThread and the stopThread() method is triggered by a SIGNAL/SLOT connection from the main thread.
// **********************************************
void CCheckForService::run()
{
SC_HANDLE SCHandle = ::OpenSCManager( 0
, SERVICES_ACTIVE_DATABASE
, SC_MANAGER_ENUMERATE_SERVICE
);
if ( 0 != SCHandle )
{
meStatus = Status::BEFORE_NOTIFY_SVC_CHANGE;
SERVICE_STATUS_PROCESS ssp;
char text[] = "MyServiceToLookFor";
wchar_t wtext[ 20 ];
mbstowcs( wtext, text, strlen( text ) + 1 );
LPWSTR lpWText = wtext;
SERVICE_NOTIFY serviceNotify = { SERVICE_NOTIFY_STATUS_CHANGE
, &CCheckForIIoT::callback
, nullptr
, 0
, ssp
, 0
, lpWText
};
// Callback function is to be invoked if "MyServiceToLookFor" has been installed
const DWORD result = ::NotifyServiceStatusChange( SCHandle
, SERVICE_NOTIFY_CREATED
, &serviceNotify
);
if ( ERROR_SUCCESS == result )
{
meStatus = Status::WAITING_FOR_CALLBACK;
::SleepEx( INFINITE, true ); // Wait for the callback function
}
LocalFree( lpWText );
}
::CloseServiceHandle( SCHandle );
if ( Status::CANCELLED != meStatus )
{
// inform main thread
emit sendReady( meStatus );
}
}
// **********************************************
// [static]
void CCheckForService::stopSleeping( ULONG_PTR in )
{
Q_UNUSED( in )
meStatus = Status::CANCELLED;
}
// **********************************************
// [static]
void CCheckForService::callback( void* apParam )
{
auto lpServiceNotify = static_cast< SERVICE_NOTIFY* >( apParam );
// the service is now installed; now wait until it runs
{
QtServiceController lBrokerService( "MyServiceToLookFor" );
QTime WaitTime;
WaitTime.start();
while ( !lBrokerService.isRunning() )
{
msleep( 1000 );
// Timeout check
if ( WaitTime.elapsed() > WAIT_FOR_SERVICE_RUN * 1000 )
{
break;
}
}
}
meStatus = Status::OK;
}
// **********************************************
// [SLOT]
void CCheckForService::stopThread( void )
{
HANDLE ThreadHandle( ::OpenThread( THREAD_ALL_ACCESS
, true
, ::GetCurrentThreadId()
)
);
DWORD d = ::QueueUserAPC( &CCheckForIIoT::stopSleeping
, ThreadHandle
, NULL
);
::CloseHandle( ThreadHandle );
}
I'm not 100% sure on this, given that you didn't provide a runnable example it's hard to verify.
My guess is that you're scheduling the APC on the main thread, instead of the CCheckForService thread.
If CCheckForService::stopThread is called from a signal/slot on the main thread, then it'll execute on the main thread.
So ::GetCurrentThreadId() will return the thread id of the main thread, and you subsequently end up with calling QueueUserAPC() with a thread handle for the main thread, so the APC will execute on the main thread.
So the CCheckForService will remain sleeping, because it never received an APC.
You can verify this by comparing QApplication::instance()->thread() with QThread::currentThread() inside your CCheckForService::stopSleeping method - if they're equal you scheduled the APC on the main thread instead of the worker.
There's unfortunately no officially supported way in QT to get the thread id / thread handle of a QThread, apart from calling QThread::currentThreadId().
So you'd have to store the thread id in your CCheckForService class, so you can later get the appropriate thread handle, e.g.:
// TODO: Add to CCheckForService declaration
// private: DWORD runningThreadId;
// TODO: initialize runningThreadId in constructor to 0
// 0 is guaranteed to never be a valid thread id
void CCheckForService::run() {
runningThreadId = ::GetCurrentThreadId();
/** ... Rest of original run() ... **/
}
void CCheckForService::stopThread( void )
{
HANDLE ThreadHandle( ::OpenThread( THREAD_ALL_ACCESS
, true
, runningThreadId /* <------ */
)
);
DWORD d = ::QueueUserAPC( &CCheckForIIoT::stopSleeping
, ThreadHandle
, NULL
);
::CloseHandle( ThreadHandle );
}
There's still a small race condition left in this example though - if you call stopThread() before the thread has started up & set the runningThreadId. In that case OpenThread() will fail and return NULL, so queuing the APC will fail.
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 have three threads - Thread1 prints "Good", Thread2 prints "Morning" and Thread3 prints "All". How do I use these threads to keep printing “Good Morning All” on the screen continuously?
For one, you are simply wasting resources.
However, assuming that you really need this to accomplish something more important than just printing words, here is a suggestion:
create 3 mutexes (pthread_mutex)
pthread_mutex_t m_Good, m_Morning, m_all;
pthread_mutex_init(&m_Good, NULL);
pthread_mutex_init(&m_Morning, NULL);
pthread_mutex_init(&m_All, NULL);
Lock last two mutexes
pthread_mutex_lock(&m_Morning);
pthread_mutex_lock(&m_All);
In first thread prints its message then unlock second mutex.
while(true){
if(pthread_mutex_lock(&m_Good)==0){
printf("GOOD ");
pthread_mutex_unlock(&m_Morning);
pthread_mutex_lock(&m_Good);
}
}
second thread prints message, locks its mutex and unlock third
third thread prints its message, unlock first mutex and locks third mutex
Here's a simple lock-free implementation for forcing sequential execution of threads. It uses an atomic state variable that can represent four possible states:
working = one of the threads is working
ready_for_task1 = it is task1's turn to start working
ready_for_task2 = it is task2's turn to start working
ready_for_task3 = it is task3's turn to start working
The general idea is to cycle through these states:
ready_for_task1 ->
working ->
ready_for_task2 ->
working ->
ready_for_task3 ->
working ->
ready_for_task1 ->
...
First part, define the states, declare the global atomic state, and define a guard class that performs the state transitions. The guard constructor of the guard will "busy" wait by atomically checking for its ready state and switching the state to working. The guard destructor will set the state to the next task's ready state.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <atomic>
enum State { ready_for_task1, ready_for_task2, ready_for_task3, working };
static std::atomic< State > state_;
class TransitionGuard {
public:
TransitionGuard(State start, State finish) : finish_(finish) {
State expecting = start;
while( !state_.compare_exchange_weak( expecting, working ) ) {
expecting = start;
asm("pause");
}
}
~TransitionGuard() {
state_.store( finish_ );
}
private:
const State finish_;
};
Then each thread runs their own loop, printing their word under their respective transition guard.
void * task1( void * data )
{
while( true ) {
TransitionGuard guard( ready_for_task1, ready_for_task2 );
printf( "Good" );
}
}
void * task2( void * data)
{
while( true ) {
TransitionGuard guard( ready_for_task2, ready_for_task3 );
printf( " Morning" );
}
return NULL;
}
void * task3( void * data)
{
while( true ) {
TransitionGuard guard( ready_for_task3, ready_for_task1 );
printf( " All\n" );
}
return NULL;
}
And finally, you'll want to initialize the state before creating the threads.
int main( int argc, const char ** argv )
{
state_ = ready_for_task1;
pthread_t thread1, thread2, thread3;
if( pthread_create( &thread1, NULL, task1, NULL ) )
{
fprintf( stderr, "thread1 failed to start\n" );
exit(EXIT_FAILURE);
}
if( pthread_create( &thread2, NULL, task2, NULL ) )
{
fprintf( stderr, "thread2 failed to start\n" );
exit(EXIT_FAILURE);
}
if( pthread_create( &thread3, NULL, task3, NULL ) )
{
fprintf( stderr, "thread3 failed to start\n" );
exit(EXIT_FAILURE);
}
pthread_join( thread1, NULL );
pthread_join( thread2, NULL );
pthread_join( thread3, NULL );
fprintf( stderr, "threads joined. exiting.\n" );
exit(EXIT_SUCCESS);
}
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));
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;
}
};
My application is crashing when it exits the thread function. This is how my thread is initialized:
LPTHREAD_START_ROUTINE pThreadStart = (LPTHREAD_START_ROUTINE)NotifyWindowThreadFn;
void * pvThreadData = reinterpret_cast<void *>(_pobjSerialPort);
// Create the exit notify window thread event handle.
_hNotifyWindowThreadExitEvent = ::CreateEvent(
NULL, // No security
TRUE, // Create a manual-reset event object
FALSE, // Initial state is non-signaled
NULL // No name specified
);
if ( _hNotifyWindowThreadExitEvent == NULL )
{
TRACE(_T("CreateNotifyWindow : Failed to get a handle for the exit message-only window event.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__);
return ::GetLastError();
}
// Create the notify window thread to begin execution on its own.
_hNotifyWindowThread = ::CreateThread(
NULL, // No security attributes.
0, // Use default initial stack size.
pThreadStart, // Function to execute in new thread.
pvThreadData, // Thread parameters.
0, // Use default creation settings.
NULL // Thread ID is not needed.
);
if ( _hNotifyWindowThread == NULL )
{
TRACE(_T("CreateNotifyWindow : Failed to create handle for message-only window thread.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__);
return ::GetLastError();
}
This is the portion of my thread function that gets executed:
DWORD NotifyWindowThreadFn( void * pParam )
{
static CNotifyWindow * pobjNotifyWindow = NULL;
CSerialPort * pobjSerialPort = reinterpret_cast<CSerialPort *>(pParam);
// Create notify window to handle surprize removal/insertion events...
try
{
pobjNotifyWindow = new CNotifyWindow();
}
catch ( DWORD error )
{
return error; // 1. PC gets here
}
catch ( long error )
{
return error;
}
catch ( ... )
{
return ERROR_CANNOT_MAKE;
}
/* Other stuff that is not executed due to return. */
} // 2. PC then gets here
When the application crashes, Visual Studio gives me this error message:
Windows has triggered a breakpoint in CppTestConsole.exe.
This may be due to a corruption of the heap, which indicates a bug in CppTestConsole.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while CppTestConsole.exe has focus.
The output window may have more diagnostic information.
The output window doesn't have anything especially useful. Only...
The thread 'NotifyWindowThreadFn' (0x414) has exited with code 0 (0x0).
Then it shows that a bunch of DLLs are unloaded. When I click the Break button, the PC is at the end of _CrtIsValidHeapPointer in dbgheap.c. Does anyone have any ideas as to why my application is crashing when the thread exits? Should I not be returning directly from within a threaded function? Thanks.
I might be wrong, but it seems like you're trying to create a window from a worker thread. Don't do this. Windows need the message pump in order to function, and there's only one message pump in your application -- it's in the main thread.
you should declare and define you function as : DWORD WINAPI NotifyWindowThreadFn( void * pParam )
Try using _beginthreadex instead of CreateThread:
A thread in an executable that calls
the C run-time library (CRT) should
use the _beginthreadex and
_endthreadex functions for thread management rather than CreateThread
and ExitThread; this requires the use
of the multi-threaded version of the
CRT. If a thread created using
CreateThread calls the CRT, the CRT
may terminate the process in
low-memory conditions.