Wake up sleeping thread!!

Posted on 2002-06-26
Last Modified: 2007-12-19
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


Question by:Barry Cunney
LVL 32

Expert Comment

ID: 7110283
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.
LVL 86

Expert Comment

ID: 7110353
What about using 'SuspendThread()' to put the thread to spleep and wake it up using 'ResumeThread()'?

Accepted Solution

Melange earned 120 total points
ID: 7111341
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;
LVL 17

Author Comment

by:Barry Cunney
ID: 7111483
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


Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Templates For Beginners Or How To Encourage The Compiler To Work For You Introduction This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more ad…
IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…

860 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question