Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. WaitForSingleObject best practices

WaitForSingleObject best practices

Scheduled Pinned Locked Moved C / C++ / MFC
12 Posts 4 Posters 2 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • F ForNow

    Hi I am looking to be Notified When something is downloaded to my FTP folder towards that end I have implemented FindFirstChangeNotification being a mainframe programmer its taken a while to get used that when I do a Wait I stop the entire thread So I have 2 options put the wait in a different thread or.... code a timer value other then infinite and in the case of WAIT_TIMEOUT loop "while(TRUE)" and Only "break when the object is signaled

    L Offline
    L Offline
    leon de boer
    wrote on last edited by
    #3

    Usually you don't stop an entire thread while waiting you are forced to do it with MFC, so I am guessing this is your MFC program again. Within MFC personally I would create a thread which just spins it wheels checking whatever and the thread simply posts a message back when an interesting event occurs. I wouldn't be putting the wait I would be putting the whole code that requires the wait in a thread and use messages to communicate with the MFC code. So make a proper worker thread.

    In vino veritas

    F 1 Reply Last reply
    0
    • L leon de boer

      Usually you don't stop an entire thread while waiting you are forced to do it with MFC, so I am guessing this is your MFC program again. Within MFC personally I would create a thread which just spins it wheels checking whatever and the thread simply posts a message back when an interesting event occurs. I wouldn't be putting the wait I would be putting the whole code that requires the wait in a thread and use messages to communicate with the MFC code. So make a proper worker thread.

      In vino veritas

      F Offline
      F Offline
      ForNow
      wrote on last edited by
      #4

      So you are saying creating a new thread to wait for notification is a better choice then an ifinate loop with say A 1000 millisecond in the WaitForSingleObject only breaking out of the loop when the event is signaled Truth is a new thread leaves the CPU time distribution up to Windows Thanks

      L 1 Reply Last reply
      0
      • F ForNow

        So you are saying creating a new thread to wait for notification is a better choice then an ifinate loop with say A 1000 millisecond in the WaitForSingleObject only breaking out of the loop when the event is signaled Truth is a new thread leaves the CPU time distribution up to Windows Thanks

        L Offline
        L Offline
        leon de boer
        wrote on last edited by
        #5

        It's a low priority Hotwatch .. it will always be better to do as a thread and it isn't hard

        // Define a structure to pass to thread
        typedef struct _MYWATCHERDATA {
        HWND AppWindow; // Application window to post message to
        UINT MsgId; // Your private message ID will be WM_APP + some number
        WPARAM CmdId; // Command ID .. perhaps you have multiple of these watchers
        char* FolderToWatch; // The string nominating the folder to watch
        HANDLE dwChangeHandles[2]; // These will be thread wait handles (1 for it, 1 for me to force exit)
        BOOL threadExitComplete; // Thread exit completed
        } WATCHERDATA;

        // This is the thread routine
        // Pass an initialized structure in on LPARAM Of CreateThread
        DWORD WINAPI NotifyMeOfFolderChangeThread(LPVOID lpParam) // thread procedure
        {
        BOOL exitSignal = FALSE; // Preset exit signal to false
        WATCHERDATA* watchData = (WATCHERDATA*)lpParam; // Typecast the lParam to your structure you pass in

        // Watch Handle\[0\] belongs to this thread 
        watchData->dwChangeHandles\[0\] =
        	FindFirstChangeNotification(watchData->FolderToWatch, // folder path passed in
        		FALSE,										      // no subfolders
        		FILE\_NOTIFY\_CHANGE\_FILE\_NAME);				      // watch for renaming, creating, or deleting a file
        
        if (INVALID\_HANDLE\_VALUE == watchData->dwChangeHandles\[0\])// Error something is dorked probably folder doesn't exist
        {
        	DWORD dwError = ::GetLastError();
        	// handle error
        	return dwError;
        }
        
        while (exitSignal == FALSE) {
        	// Okay we wait on the notification signal or exernal exit signal
        	DWORD dwWaitStatus = WaitForMultipleObjects(2, 
        		watchData->dwChangeHandles, FALSE, INFINITE);
        	
        	switch (dwWaitStatus) {
        		// Wait exit was from directory change
        		case WAIT\_OBJECT\_0:
        			// Post off message back to application window.
        			PostMessage(watchData->AppWindow, watchData->MsgId,
        				watchData->CmdId, (LPARAM)watchData->FolderToWatch);
        			FindNextChangeNotification(watchData->dwChangeHandles\[0\]);
        			break;
        		// External thread signal forcing thread to break out and exit
        		case WAIT\_OBJECT\_0 + 1:
        			exitSignal = TRUE;           // Yep time to exit
        			break;
        	}
        }
        watchData->threadExitComplete = TRUE; // Thread has finished with watchData .. tell app that
        return 0;
        

        }

        The use of the thread involves, initialize, use, wait for thread to exit .. cleanup

        // Initialize a WATCHERDATA structure
        char* watchDirectory = "c:\\temp\\";

        F J 3 Replies Last reply
        0
        • L leon de boer

          It's a low priority Hotwatch .. it will always be better to do as a thread and it isn't hard

          // Define a structure to pass to thread
          typedef struct _MYWATCHERDATA {
          HWND AppWindow; // Application window to post message to
          UINT MsgId; // Your private message ID will be WM_APP + some number
          WPARAM CmdId; // Command ID .. perhaps you have multiple of these watchers
          char* FolderToWatch; // The string nominating the folder to watch
          HANDLE dwChangeHandles[2]; // These will be thread wait handles (1 for it, 1 for me to force exit)
          BOOL threadExitComplete; // Thread exit completed
          } WATCHERDATA;

          // This is the thread routine
          // Pass an initialized structure in on LPARAM Of CreateThread
          DWORD WINAPI NotifyMeOfFolderChangeThread(LPVOID lpParam) // thread procedure
          {
          BOOL exitSignal = FALSE; // Preset exit signal to false
          WATCHERDATA* watchData = (WATCHERDATA*)lpParam; // Typecast the lParam to your structure you pass in

          // Watch Handle\[0\] belongs to this thread 
          watchData->dwChangeHandles\[0\] =
          	FindFirstChangeNotification(watchData->FolderToWatch, // folder path passed in
          		FALSE,										      // no subfolders
          		FILE\_NOTIFY\_CHANGE\_FILE\_NAME);				      // watch for renaming, creating, or deleting a file
          
          if (INVALID\_HANDLE\_VALUE == watchData->dwChangeHandles\[0\])// Error something is dorked probably folder doesn't exist
          {
          	DWORD dwError = ::GetLastError();
          	// handle error
          	return dwError;
          }
          
          while (exitSignal == FALSE) {
          	// Okay we wait on the notification signal or exernal exit signal
          	DWORD dwWaitStatus = WaitForMultipleObjects(2, 
          		watchData->dwChangeHandles, FALSE, INFINITE);
          	
          	switch (dwWaitStatus) {
          		// Wait exit was from directory change
          		case WAIT\_OBJECT\_0:
          			// Post off message back to application window.
          			PostMessage(watchData->AppWindow, watchData->MsgId,
          				watchData->CmdId, (LPARAM)watchData->FolderToWatch);
          			FindNextChangeNotification(watchData->dwChangeHandles\[0\]);
          			break;
          		// External thread signal forcing thread to break out and exit
          		case WAIT\_OBJECT\_0 + 1:
          			exitSignal = TRUE;           // Yep time to exit
          			break;
          	}
          }
          watchData->threadExitComplete = TRUE; // Thread has finished with watchData .. tell app that
          return 0;
          

          }

          The use of the thread involves, initialize, use, wait for thread to exit .. cleanup

          // Initialize a WATCHERDATA structure
          char* watchDirectory = "c:\\temp\\";

          F Offline
          F Offline
          ForNow
          wrote on last edited by
          #6

          thanks so much

          1 Reply Last reply
          0
          • L leon de boer

            It's a low priority Hotwatch .. it will always be better to do as a thread and it isn't hard

            // Define a structure to pass to thread
            typedef struct _MYWATCHERDATA {
            HWND AppWindow; // Application window to post message to
            UINT MsgId; // Your private message ID will be WM_APP + some number
            WPARAM CmdId; // Command ID .. perhaps you have multiple of these watchers
            char* FolderToWatch; // The string nominating the folder to watch
            HANDLE dwChangeHandles[2]; // These will be thread wait handles (1 for it, 1 for me to force exit)
            BOOL threadExitComplete; // Thread exit completed
            } WATCHERDATA;

            // This is the thread routine
            // Pass an initialized structure in on LPARAM Of CreateThread
            DWORD WINAPI NotifyMeOfFolderChangeThread(LPVOID lpParam) // thread procedure
            {
            BOOL exitSignal = FALSE; // Preset exit signal to false
            WATCHERDATA* watchData = (WATCHERDATA*)lpParam; // Typecast the lParam to your structure you pass in

            // Watch Handle\[0\] belongs to this thread 
            watchData->dwChangeHandles\[0\] =
            	FindFirstChangeNotification(watchData->FolderToWatch, // folder path passed in
            		FALSE,										      // no subfolders
            		FILE\_NOTIFY\_CHANGE\_FILE\_NAME);				      // watch for renaming, creating, or deleting a file
            
            if (INVALID\_HANDLE\_VALUE == watchData->dwChangeHandles\[0\])// Error something is dorked probably folder doesn't exist
            {
            	DWORD dwError = ::GetLastError();
            	// handle error
            	return dwError;
            }
            
            while (exitSignal == FALSE) {
            	// Okay we wait on the notification signal or exernal exit signal
            	DWORD dwWaitStatus = WaitForMultipleObjects(2, 
            		watchData->dwChangeHandles, FALSE, INFINITE);
            	
            	switch (dwWaitStatus) {
            		// Wait exit was from directory change
            		case WAIT\_OBJECT\_0:
            			// Post off message back to application window.
            			PostMessage(watchData->AppWindow, watchData->MsgId,
            				watchData->CmdId, (LPARAM)watchData->FolderToWatch);
            			FindNextChangeNotification(watchData->dwChangeHandles\[0\]);
            			break;
            		// External thread signal forcing thread to break out and exit
            		case WAIT\_OBJECT\_0 + 1:
            			exitSignal = TRUE;           // Yep time to exit
            			break;
            	}
            }
            watchData->threadExitComplete = TRUE; // Thread has finished with watchData .. tell app that
            return 0;
            

            }

            The use of the thread involves, initialize, use, wait for thread to exit .. cleanup

            // Initialize a WATCHERDATA structure
            char* watchDirectory = "c:\\temp\\";

            F Offline
            F Offline
            ForNow
            wrote on last edited by
            #7

            Leon Just wanted to tell you again you are correct I have Sockets in my code So Typically after I do CAsynSocket connect I do the send after I get the OnSend Notification From The FrameWork My Sockets has a CWinThread Wrapper, However the notification like OnSend comes in The Context of the Main Thread Since I put WaitFor...Object api (In The Main Thread) even though I didn't have INFINITE it messed up the Windows Dispatcher and I wasn't getting the notification I am going to try your code out Shortly Thanks again

            L 2 Replies Last reply
            0
            • F ForNow

              Leon Just wanted to tell you again you are correct I have Sockets in my code So Typically after I do CAsynSocket connect I do the send after I get the OnSend Notification From The FrameWork My Sockets has a CWinThread Wrapper, However the notification like OnSend comes in The Context of the Main Thread Since I put WaitFor...Object api (In The Main Thread) even though I didn't have INFINITE it messed up the Windows Dispatcher and I wasn't getting the notification I am going to try your code out Shortly Thanks again

              L Offline
              L Offline
              leon de boer
              wrote on last edited by
              #8

              Yes that is a generic schema for not doing that sort of thing ... I hacked the MSDN thread sample. When I do socket apps I do exactly the same schema I have a write thread and a read thread of exactly the form above. The socket IO structures and objects are held in the memory block. Basically you want your app just dealing with messages not sitting around doing things .. bring up task manager and look at the number of threads running normally. It really expects and wants this sort of behaviour, it's designed around it. Lifetime of app threads in particular are extremely easy because you can launch them on the WM_CREATE of the main app window and dispose of them in the WM_DESTROY. You don't have the problem of who is responsible for the shared data and memory (and it's cleanup) that you have with intermittent start and stop threads. The app window handle to pass to the thread to message you also can't get wrong :-) They give you huge blocks of message ids at WM_APP and WM_USER to allow you to do it. All those ID's you are free to use but you might want to check MFC might use a few (that is why I jumped 100) and they may restrict the range down a little.

              In vino veritas

              1 Reply Last reply
              0
              • F ForNow

                Leon Just wanted to tell you again you are correct I have Sockets in my code So Typically after I do CAsynSocket connect I do the send after I get the OnSend Notification From The FrameWork My Sockets has a CWinThread Wrapper, However the notification like OnSend comes in The Context of the Main Thread Since I put WaitFor...Object api (In The Main Thread) even though I didn't have INFINITE it messed up the Windows Dispatcher and I wasn't getting the notification I am going to try your code out Shortly Thanks again

                L Offline
                L Offline
                leon de boer
                wrote on last edited by
                #9

                Present for you as I checked my code putting it into an application Code: Folder watcher code[^] Compiled EXE:Folder HotWatcher EXE[^] It's a full folder watcher app with a basic watcher thread and detailed watcher thread. Basic just tells you if the folder changed, Detailed tells you file changes and what action was done. Basically run the app select an unimportant directory like c:\temp and then copy, delete, rename files to the directory and you will see the messages reported to the app.

                In vino veritas

                F 1 Reply Last reply
                0
                • L leon de boer

                  Present for you as I checked my code putting it into an application Code: Folder watcher code[^] Compiled EXE:Folder HotWatcher EXE[^] It's a full folder watcher app with a basic watcher thread and detailed watcher thread. Basic just tells you if the folder changed, Detailed tells you file changes and what action was done. Basically run the app select an unimportant directory like c:\temp and then copy, delete, rename files to the directory and you will see the messages reported to the app.

                  In vino veritas

                  F Offline
                  F Offline
                  ForNow
                  wrote on last edited by
                  #10

                  leon thanks so much I implemented the code and problems went away meaning with out the wait in the Main Thread The Framework was able to notify me via CAsynSocket::OnSend The actual testing will come when I execute my Z/OS (MainFrame) FTP code to download the file to that folder that is being watched Much thanks

                  J 1 Reply Last reply
                  0
                  • L leon de boer

                    It's a low priority Hotwatch .. it will always be better to do as a thread and it isn't hard

                    // Define a structure to pass to thread
                    typedef struct _MYWATCHERDATA {
                    HWND AppWindow; // Application window to post message to
                    UINT MsgId; // Your private message ID will be WM_APP + some number
                    WPARAM CmdId; // Command ID .. perhaps you have multiple of these watchers
                    char* FolderToWatch; // The string nominating the folder to watch
                    HANDLE dwChangeHandles[2]; // These will be thread wait handles (1 for it, 1 for me to force exit)
                    BOOL threadExitComplete; // Thread exit completed
                    } WATCHERDATA;

                    // This is the thread routine
                    // Pass an initialized structure in on LPARAM Of CreateThread
                    DWORD WINAPI NotifyMeOfFolderChangeThread(LPVOID lpParam) // thread procedure
                    {
                    BOOL exitSignal = FALSE; // Preset exit signal to false
                    WATCHERDATA* watchData = (WATCHERDATA*)lpParam; // Typecast the lParam to your structure you pass in

                    // Watch Handle\[0\] belongs to this thread 
                    watchData->dwChangeHandles\[0\] =
                    	FindFirstChangeNotification(watchData->FolderToWatch, // folder path passed in
                    		FALSE,										      // no subfolders
                    		FILE\_NOTIFY\_CHANGE\_FILE\_NAME);				      // watch for renaming, creating, or deleting a file
                    
                    if (INVALID\_HANDLE\_VALUE == watchData->dwChangeHandles\[0\])// Error something is dorked probably folder doesn't exist
                    {
                    	DWORD dwError = ::GetLastError();
                    	// handle error
                    	return dwError;
                    }
                    
                    while (exitSignal == FALSE) {
                    	// Okay we wait on the notification signal or exernal exit signal
                    	DWORD dwWaitStatus = WaitForMultipleObjects(2, 
                    		watchData->dwChangeHandles, FALSE, INFINITE);
                    	
                    	switch (dwWaitStatus) {
                    		// Wait exit was from directory change
                    		case WAIT\_OBJECT\_0:
                    			// Post off message back to application window.
                    			PostMessage(watchData->AppWindow, watchData->MsgId,
                    				watchData->CmdId, (LPARAM)watchData->FolderToWatch);
                    			FindNextChangeNotification(watchData->dwChangeHandles\[0\]);
                    			break;
                    		// External thread signal forcing thread to break out and exit
                    		case WAIT\_OBJECT\_0 + 1:
                    			exitSignal = TRUE;           // Yep time to exit
                    			break;
                    	}
                    }
                    watchData->threadExitComplete = TRUE; // Thread has finished with watchData .. tell app that
                    return 0;
                    

                    }

                    The use of the thread involves, initialize, use, wait for thread to exit .. cleanup

                    // Initialize a WATCHERDATA structure
                    char* watchDirectory = "c:\\temp\\";

                    J Offline
                    J Offline
                    Joe Woodbury
                    wrote on last edited by
                    #11

                    while (myWatch->threadExitComplete == FALSE) {};

                    In this example,

                    WaitForSingleObject(workerThread, INFINITE)

                    would be better. For the handle array in the thread, prefer putting the stop event first to ensure it has a higher priority. I'd also directly test:

                    if (dwWaitStatus == WAIT_OBJECT_0)
                    break;

                    Since you aren't looking at any other conditions, you don't need to check for them.

                    1 Reply Last reply
                    0
                    • F ForNow

                      leon thanks so much I implemented the code and problems went away meaning with out the wait in the Main Thread The Framework was able to notify me via CAsynSocket::OnSend The actual testing will come when I execute my Z/OS (MainFrame) FTP code to download the file to that folder that is being watched Much thanks

                      J Offline
                      J Offline
                      Joe Woodbury
                      wrote on last edited by
                      #12

                      Be aware that the change folder notification occurs at any change, which means the full write may not have happened. One solution is to write the file to another location and then atomically move it to the monitored directory.

                      1 Reply Last reply
                      0
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • World
                      • Users
                      • Groups