Wake up sleeping thread!!

Hi Guys,
I have the following thread function which works reasonably well but I am trying to improve it.
Basically it is a continous thread in a while(true) loop as I want to continously monitor something.
It first executes an SQL Server Stored Procedure which I have written(see content below - sp_chkTenforeFeed), that creates and executes an SQL Profiler trace.
I then put the application to sleep for 2 minutes to allow the SQL Profiler trace queue to run giving me a 2 minute snapshot of trace output in a .trc file.
After the 2 minutes I execute another Stored Procedure which I have written(see content below - sp_stopchkTenforeFeed) to stop and destroy Profiler trace queue. I have to do this to free up .trc file allowing it to be moved to local drive(It cannot be moved if a Profiler trace queue is still adding to it)

Then the TenforeFeed.trc is moved to the local drive to be interrogated.
I sleep again for 30 seconds as I want a 30 second interval between each trace.

I have a 'Stop Monitor' menu option which the user can use to stop(Sets an end event) this trace(note line of code with 'WaitForSingleObject(tis->pEndEvent->m_hObject,0') thread but if the user clicks this option when the thread has gone into the 2 minute sleep above it is not until it comes out of this sleep that it realises the end event has been set and then shuts itself down.

What I want to know is, if there is a way that I can write this thread function so as it can be woken up if sleeping and stopped immediately. Also before stopping it I want to stop current trace queue and delete .trc file.
In this way the user gets a more instant shutdown.

See code below as well as Stored Procedures.
If any point is unclear or if you need additional inforation, please let me know

I have been looking at SleepEx, WaitforSingleObjectEx but I am not sure if or how I can use these in this situation.

This is how I am creating thread - I have 'Start Monitor menu option to do this (My application is an MFC dialog based application) - (I am relatively new to c++!!)

      tis->someData="Monitor Running";
      CWinThread *pThread = AfxBeginThread(TraceThreadFunc,tis,

// Thread function which manages Profiler Trace//
UINT TraceThreadFunc(LPVOID lParam)
      int iQHndl;
      VARIANT vtQHndl;      
      vtQHndl.vt = VT_I2;      
      _CommandPtr pCommand2;
      _RecordsetPtr rs;       
      //run forever--or until stop monitor event is set
            // COM initialization
            CoInitialize (NULL);

            // Wait to see if end event has been set
            if (::WaitForSingleObject(tis->pEndEvent->m_hObject,0)==WAIT_OBJECT_0) {
                  delete tis;
                  return (UINT)-1;
            // Send a message to indicate that the trace is running
            //<------------------ Procedure to run SQL Server Profiler Trace -------------------------->

            // Establishing a connection to the datasource
                  HRESULT hr = m_pConn.CreateInstance (__uuidof(Connection));
                  if (FAILED (hr))
                        wsprintf( szMsg, "CreateInstance failed." );
                        MessageBox( NULL, szMsg, "main", MB_OK );

                  if (FAILED (m_pConn->Open (_bstr_t ("Provider=MSDASQL;DSN=Support;UID=sa;PWD=elijah;"),
                              _bstr_t (""), _bstr_t (""), adModeUnknown)))
                        wsprintf( szMsg, "Cannot open data source" );
                        MessageBox( NULL, szMsg, "main", MB_OK );
            catch ( _com_error &e )
                  _bstr_t bstrSource (e.Source());
                  _bstr_t bstrDescription (e.Description());
            // Execute SQL Server Stored Procedure which executes SQL Profiler trace
                  _CommandPtr pCommand;
                  _ParameterPtr   Param1;
                  HRESULT hr = pCommand.CreateInstance(__uuidof(Command));

                  if (FAILED(hr))
                        wsprintf( szMsg, "CreateInstance failed." );
                        MessageBox( NULL, szMsg, "main", MB_OK );

                  pCommand->ActiveConnection = m_pConn;
                  pCommand->CommandType = adCmdStoredProc;
                  pCommand->CommandText = "sp_chkTenforeFeed";
                  Param1 = pCommand->CreateParameter(_bstr_t("o_id"),adInteger,adParamReturnValue, sizeof(int), vtQHndl);

                  pCommand->Execute(NULL, NULL, adCmdStoredProc);
                  iQHndl = Param1->GetValue().iVal;
                  vtQHndl.iVal = iQHndl;

                  Sleep(120000);            // Sleep for 2 minutes to let
                                                            // SQL Profiler Trace run to
                                                            // produce a 2 minute snapshot of trace output
                                                            // in a .trc file
                  // Then call stored procedure which stops and destroys
                  // SQL Profiler trace queue and move trace file(.trc file) to local drive
                  // to be interrogated
                  HRESULT hr2 = pCommand2.CreateInstance(__uuidof(Command));

                  if (FAILED(hr2))
                        wsprintf( szMsg, "CreateInstance failed." );
                        MessageBox( NULL, szMsg, "main", MB_OK );

                  pCommand2->ActiveConnection = m_pConn;
                  pCommand2->CommandType = adCmdStoredProc;
                  pCommand2->CommandText = "sp_stopchkTenforeFeed";
                  _ParameterPtr   Param2;
                  Param2 = pCommand2->CreateParameter(_bstr_t("i_id"), adInteger, adParamInput, sizeof(int), vtQHndl);
                  Param2->Value = vtQHndl ;

                  rs = pCommand2->Execute(NULL, NULL, adCmdStoredProc);

            catch( _com_error &e )
                  _bstr_t bstrSource(e.Source());
                  _bstr_t bstrDescription(e.Description());

            // Move file to local drive  and interrogate file
            MoveFileEx("J:\\TenforeFeed.trc", "C:\\TenforeFeed.trc",

  Sleep(30000);      // Allow 30 seconds between execution of each trace

      } // while(true) loop


CREATE Procedure sp_chkTenforeFeed as
DECLARE @column_value int
SET @column_value =  67108864|1
DECLARE @queue_handle int
EXEC master..xp_trace_addnewqueue 11000, 10000, 95, 90, @column_value,  @queue_handle OUTPUT
EXEC master..xp_trace_seteventclassrequired @queue_handle, 11 ,1 -- RPC:Starting
EXEC master..xp_trace_seteventclassrequired @queue_handle, 10 ,1 -- RPC:Ending
--EXEC master..xp_trace_seteventclassrequired @queue_handle, 31 ,1 -- Select

EXEC master..xp_trace_setappfilter @queue_handle, 'WITS Money Application Server', 'SQL Server Profiler%'

EXEC master..xp_trace_setqueuedestination @queue_handle, 2,1, NULL, 'e:\TenforeFeed.trc'

EXEC master..xp_trace_startconsumer @queue_handle

return @queue_handle


CREATE Procedure sp_stopchkTenforeFeed
  @queue_handle Int


EXEC master..xp_trace_pausequeue @queue_handle
EXEC master..xp_trace_destroyqueue @queue_handle


LVL 17
Barry CunneyAsked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

MelangeConnect With a Mentor Commented:
The only problem with using a timer for "sleeping" is that SetTimer requires a message loop (even for function notification, I believe).

As jhance touched on, the best way for a background thread to "sleep" until needed is simply to wait on an event using WaitForSingleObject or WaitForMultipleObject. Then when the main thread needs to wake up the thread, simply call SetEvent.

You can use a timeout value in the WaitForSingleObject if the background thread wants to periodically wake up on its own for some processing.

From a quick glance at your code, replace Sleep(12000) with:

if( WaitForSingleObject(tis->pEndEvent->m_hObject, 12000) != WAIT_TIMEOUT )
   abort or something;
Very confusing question and I think you're posted WAY too much code for clarity.

I think the basic problem is that you're calling Sleep().  It's my opinion that Sleep() should NEVER be used in a Windows (or other multi-taking/GUI) system.  There are BETTER methods of waiting for things to happen.  These include, but are not limited to:

1) WaitForSingleObject() and its relatives
2) MUTEXes, semaphores, critical sections, etc.
3) Setting a TIMER.

The biggest problem with Sleep() is that the thread calling Sleep() stops until the interval expires.  There is no way to "wake-up" from a Sleep() call other than KILLING the thread.  But that's a drastic action and generally is not what you want anyway.

I'm sure that whatever you're waiting on has a signalling mechanism that you can use to trigger your thread to continue.  But even if not, the BEST way to wait/poll in Windows is to set a timer and then look at whatever you are polling at each timer tick.  So if you want to wait up to 2 minutes, you could set a timer for 1 sec interval, check your status every 1 sec., and then continue if the event has passed.  That way you can, in effect, wake-up with 1 sec. granularity.  If you need to be more responsive, set a shorter timer.
What about using 'SuspendThread()' to put the thread to spleep and wake it up using 'ResumeThread()'?
Barry CunneyAuthor Commented:
Thanks Melange
This is exactly what I needed.
I never thought of putting a WaitForSingleObject with interval instead of Sleep.
I have changed code with your suggestion and put trace cleanup code inside ' if( WaitForSingleObject(tis->pEndEvent->m_hObject, 12000) != WAIT_TIMEOUT )
which stops my trace queue and deletes trace file.

I also put a similar wait for my other Sleep as well

This is brilliant, so now my thread is never sleeping and is always ready to respond to end event giving user an instant shutdown and also cleans up everything.

I had said in my original question that I am relatively new to c++ and in particular threads, so I am not yet totally sharp on how to use various thread functions such as WaitForSingleObject although I do understand the basic concepts - experience is invaluable

Many Thanks again Melange

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.