[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 332
  • Last Modified:

Thread termination problem.

Hi

I started a thread to check for a file change using the below code

CWinThread* m_UpdateMonitorThread = AfxBeginThread(CheckFileUpdates,(LPVOID)this)

UINT CheckFileUpdates(LPVOID lp)
{
                        while( ReadDirectoryChangesW(
            hDir,                                  // handle to directory
            &Buffer,                                    // read results buffer
            sizeof(Buffer),                                // length of buffer
            TRUE,                                // monitoring option
            FILE_NOTIFY_CHANGE_SIZE,                            // filter conditions
            &BytesReturned,              // bytes returned
            NULL,                          // overlapped buffer
            NULL// completion routine
            ))
{
//do the work

}
}

Now on I have abutton on my UI. Onclick of the button I want to stop the above thread.

I I tried to use
if(m_UpdateMonitorThread)
{
        DWORD dwRetCode;
        while (!GetExitCodeThread(m_UpdateMonitorThread->m_hThread, &dwRetCode));
        TerminateThread(m_UpdateMonitorThread->m_hThread,dwRetCode);      
         m_UpdateMonitorThread = NULL;
}
and

if(m_UpdateMonitorThread)
{
      m_UpdateMonitorThread->SuspendThread();
      m_UpdateMonitorThread->Delete();
      m_UpdateMonitorThread = NULL;

}

I am getting memory leaks in both the above cases. I tried to post a Stop Event, but where do I wait for this event inside the thread code as execution will not go inside the while loop code because of ReadDirectoryChangesW.  

Can anyone please please suggest a way out to this problem.
Thanks in anticipation of information.

Madhavi
0
l_madhavi
Asked:
l_madhavi
  • 4
  • 3
1 Solution
 
AlexFMCommented:
TerminateThread kills worker thread and doesn't give chance to make cleanup operations. This function may be used only to stop threads which are not responding. Right way is to ask thread to stop and wait when it exits. Your code should look like this:

HANDLE m_hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
CWinThread* m_UpdateMonitorThread = AfxBeginThread(CheckFileUpdates,(LPVOID)this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
m_UpdateMonitorThread->m_bAutoDelete = FALSE;
m_UpdateMonitorThread->ResumeThread( );

#define MAX_WAIT 5000

UINT CheckFileUpdates(LPVOID lp)
{
    CMyClass* pClass = (CMyClass*)p;

    while( ReadDirectoryChangesW(
          hDir,                                  // handle to directory
          &Buffer,                                    // read results buffer
          sizeof(Buffer),                                // length of buffer
          TRUE,                                // monitoring option
          FILE_NOTIFY_CHANGE_SIZE,                            // filter conditions
          &BytesReturned,              // bytes returned
          NULL,                          // overlapped buffer
          NULL// completion routine
          ))
    {
        //do the work

        // test for stop flag
        if ( WaitForSingleObject(pClass->m_hStopEvent) == WAIT_OBJECT_O )
        {
             // main thread wants to stop this thread
             break;   // exit loop and thread function
        }
    }
}

Stop worker thread:

if(m_UpdateMonitorThread)
{
    SetEvent(m_hStopEvent);    // ask thread to stop

    // wait when thread really exits
    if ( WaitForSingleObject(m_UpdateMonitorThread ->m_hThread, MAX_WAIT) != WAIT_OBJECT_0 )
    {
         // Thread is not responding - kill it. However, program should never execute this branch!
         // Report error by some way - TRACE, message box, log etc.
         // Kill thread to keep the whole program responsive.
         TerminateThread(m_UpdateMonitorThread->m_hThread, 0);    
    }

    delete m_UpdateMonitorThread;
   m_UpdateMonitorThread = NULL;
}

Your worker thread function may be not resposive for a long time when ReadDirectoryChangesW is executed. You must rewrite is using overlapped I/O, so that it will exit immidiately when m_hStopEvent is set. Use OVERLAPPED structure, and wait for two events: OVERLAPPED event and m_hStopEvent.
0
 
l_madhaviAuthor Commented:
Hi AlexFM

Thanks for your quick response.   I used the same code as shown below
UINT CheckFileUpdates(LPVOID lp)
{
      //Get the document pointer
      CLogViewerAppView* pView = (CLogViewerAppView*)lp;
      CLogViewerAppDoc* pDoc = pView->GetDocument();
         
      CFileException err;
      CFileStatus st;
      CFile::GetStatus(pView->m_LogFilePath,st);
      LONG l1,l2;
      
      CFile file;
      if( !file.Open(pView->m_LogFilePath, CFile::modeRead|CFile::shareDenyNone, &err ) )
      {
            TCHAR   szCause[255];      
            err.GetErrorMessage(szCause, 255);      
            AfxMessageBox(szCause);      
            return 0;
      }
      l1 = (LONG)file.GetLength();
      file.Close();
      CFile file1;
      LONG size_1 = (LONG)st.m_size;
      int len = pView->m_LogFilePath.GetLength()-pView->m_LogFileName.GetLength()-1;
      CString dir = pView->m_LogFilePath.Left(len);
      HANDLE hDir = CreateFile( dir, // pointer to the file name
            FILE_LIST_DIRECTORY,                // access (read/write) mode
            FILE_SHARE_READ|FILE_SHARE_WRITE,  // share mode
            NULL,                               // security descriptor
            OPEN_EXISTING,                      // how to create
            FILE_FLAG_BACKUP_SEMANTICS,         // file attributes
            NULL                                // file with attributes to copy
            );

      FILE_NOTIFY_INFORMATION Buffer[1024];
      DWORD BytesReturned;

      while( ReadDirectoryChangesW(
            hDir,                                  // handle to directory
            &Buffer,                                    // read results buffer
            sizeof(Buffer),                                // length of buffer
            TRUE,                                // monitoring option
            FILE_NOTIFY_CHANGE_SIZE,                            // filter conditions
            &BytesReturned,              // bytes returned
            NULL,                          // overlapped buffer
            NULL// completion routine
            ))
      {
            if ( WaitForSingleObject(pView->m_StopEvent, INFINITE) == WAIT_OBJECT_0 )
                                    {
                  OutputDebugString(_T("\n KIIGSRETG \n"));
                                                         return 0; //end the thraed
           
                                      }

            CString fileName(Buffer[0].FileName);
            fileName = fileName.Left(Buffer[0].FileNameLength / 2);

            if(fileName.CompareNoCase(pView->m_LogFileName) == 0)
            {
                  //Do the work
            }            
      }
      
      return 0;
}

But the m_StopEvent event is not caught beacuse the control is stuck at while( ReadDirectoryChangesW) I mean it not going inside the while loop unless ReadDirectoryChangesW returns true. Hence WaitForSingleObject is not checked at all.. Hope you got my point.

Please help me to proceed further.

Thanks
Madhavi
0
 
AlexFMCommented:
Last lines of my previous post:

Your worker thread function may be not resposive for a long time when ReadDirectoryChangesW is executed. You must rewrite is using overlapped I/O, so that it will exit immidiately when m_hStopEvent is set. Use OVERLAPPED structure, and wait for two events: OVERLAPPED event and m_hStopEvent.
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
l_madhaviAuthor Commented:
You must rewrite is using overlapped I/O, so that it will exit immidiately when m_hStopEvent is set. Use OVERLAPPED structure, and wait for two events: OVERLAPPED event and m_hStopEvent.

--------- Can you please let me know how to write this using  OVERLAPPED structure. I never did this before. I am stuck at this point..unable to proceed further.

Thanks
Madhavi..
0
 
AlexFMCommented:
LPOVERLAPPED overlapped;
overlapped.hEvent = CreateEvent((NULL, TRUE, FALSE, NULL);
if ( ! ReadDirectoryChangesW(... &overlapped ... ) )
{
    // handle error
}
else
{
     BOOL bResult = GetOverlappedResult(...);

     if ( bResult )
     {
          // succeeded immidiately, handle results here
     }
     else
     {
           if ( GetLastError() == ERROR_IO_PENDING )
           {
              // wait for overlapped and stop events
              HANDLE handles[1];
              handles[0] = overlapped.hEvent;
              handles[1] = pView->m_StopEvent;

              DWORD dwResult = WaitForMultipleObjects(2, handles, FALSE, INFINITE);

              switch ( dwResult )
              {
                  case WAIT_OBJECT_0:
                       // overlapped.hEvent is signaled
                       // handle results
                       // ...
                       break;

                  case WAIT_OBJECT_1:
                       // overlapped.hEvent is signaled
                       // pView->m_StopEvent is signaled
                       // exit from loop and return thread function !
                       // ...
                       break;
                  default:
                       // handle error
               }
           }
           else
           {
                // handle error
           }
     }
}
0
 
l_madhaviAuthor Commented:
Thanks fo rthe code.

Below is my code. I am still having problems. Th echange event is not beign detected.

UINT CheckFileUpdates(LPVOID lp)
{
      //Get the document pointer
      CLogViewerAppView* pView = (CLogViewerAppView*)lp;
      CLogViewerAppDoc* pDoc = pView->GetDocument();
      DWORD BytesReturned;
      //Create a critical section object
      CSingleLock csl(&pView->m_UpdateCSect);

      CFileException err;
      CFileStatus st;
      CFile::GetStatus(pView->m_LogFilePath,st);
      LONG l1,l2;

      CFile file;
      if( !file.Open(pView->m_LogFilePath, CFile::modeRead|CFile::shareDenyNone, &err ) )
      {
            TCHAR   szCause[255];      
            err.GetErrorMessage(szCause, 255);      
            AfxMessageBox(szCause);      
            return 0;
      }
      l1 = (LONG)file.GetLength();
      file.Close();
      CFile file1;
      LONG size_1 = (LONG)st.m_size;
      int len = pView->m_LogFilePath.GetLength()-pView->m_LogFileName.GetLength()-1;
      CString dir = pView->m_LogFilePath.Left(len);
      HANDLE hDir = CreateFile( dir, // pointer to the file name
            FILE_LIST_DIRECTORY,                // access (read/write) mode
            FILE_SHARE_READ|FILE_SHARE_WRITE  ,  // share mode
            NULL,                               // security descriptor
            OPEN_EXISTING,                      // how to create
            FILE_FLAG_BACKUP_SEMANTICS,         // file attributes
            NULL                                // file with attributes to copy
            );

      FILE_NOTIFY_INFORMATION Buffer[1024];

      ////////////////////////////////////=============
      OVERLAPPED overlapped;
      overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
      while(1)
      {
            if(!ReadDirectoryChangesW(
                  hDir,                                  // handle to directory
                  &Buffer,                                    // read results buffer
                  sizeof(Buffer),                                // length of buffer
                  TRUE,                                // monitoring option
                  FILE_NOTIFY_CHANGE_SIZE,     // filter conditions
                  &BytesReturned,              // bytes returned
                  &overlapped,// overlapped buffer
                  NULL// completion routine
                  ) )
            {
                  // handle error
            }
            else
            {
                  BOOL bResult = GetOverlappedResulthDir,&overlapped,NULL,TRUE);

                  if ( bResult )
                  {
                        // succeeded immidiately, handle results here
                  }
                  else
                  {
                        if ( GetLastError() == ERROR_IO_PENDING )
                        {
                              // wait for overlapped and stop events
                              HANDLE handles[1];
                              handles[0] = overlapped.hEvent;
                              handles[1] = pView->m_StopEvent;
                              DWORD dwResult = WaitForMultipleObjects(2, handles, FALSE, INFINITE);

                              switch ( dwResult )
                              {
                              case WAIT_OBJECT_0 + 0:
                                    AfxMessageBox(_T(" Fired"));
                                    break;

                              case WAIT_OBJECT_0 +1:
                                    // overlapped.hEvent is signaled
                                    // pView->m_StopEvent is signaled
                                    // exit from loop and return thread function !
                                    // ...
                                    return 0;
                                    break;
                              default:
                                    break;
                                    // handle error
                              }
                        }
                        else
                        {
                              // handle error
                        }
                  }
            }
      }

      return 0;
}
Can you please let me know if I am wrong anywhere?

Thanks
Madhavi
0
 
AlexFMCommented:
A call to ReadDirectoryChangesW can be completed synchronously or asynchronously. To specify asynchronous completion, open the directory with CreateFile as shown above, but additionally specify the FILE_FLAG_OVERLAPPED attribute in the dwFlagsAndAttributes parameter. Then specify an OVERLAPPED structure when you call ReadDirectoryChangesW.

And add some real code instead of my notes like
// handle error
// exit from loop and return thread function

This can help.

BTW, don't forget to release overlapped.hEvent.
0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

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.

  • 4
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now