Solved

Wake up sleeping thread!!

Posted on 2002-06-26
4
1,577 Views
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++!!)

THREADINFOSTRUCT *tis=new THREADINFOSTRUCT;
      
      tis->hWnd=m_hWnd;
            tis->pEndEvent=&m_endEvent;
      tis->someData="Monitor Running";
      
      CWinThread *pThread = AfxBeginThread(TraceThreadFunc,tis,
            THREAD_PRIORITY_NORMAL,0,0);

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

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

            // Establishing a connection to the datasource
            try
            {
                  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
            try
            {
                  _CommandPtr pCommand;
                  _ParameterPtr   Param1;
            
                  HRESULT hr = pCommand.CreateInstance(__uuidof(Command));

                  if (FAILED(hr))
                  {
                        wsprintf( szMsg, "CreateInstance failed." );
                        MessageBox( NULL, szMsg, "main", MB_OK );
                        return(-1);
                  }

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

                  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 );
                        return(-1);
                  }

                  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 ;
                   pCommand2->Parameters->Append(Param2);

                  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",
                  MOVEFILE_COPY_ALLOWED|MOVEFILE_REPLACE_EXISTING|MOVEFILE_WRITE_THROUGH);
            
            //<------------------------------------------------------------------------->//

  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
)

as

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

-----------------------------------------------------------------------------------------------------------------

0
Comment
Question by:Barry Cunney
4 Comments
 
LVL 32

Expert Comment

by:jhance
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.
0
 
LVL 86

Expert Comment

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

Accepted Solution

by:
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;
0
 
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

 
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

760 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

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now