WaitForSingleObject best practices
-
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
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
-
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
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
-
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
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\\"; -
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\\"; -
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\\";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
-
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
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
-
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
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
-
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
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
-
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\\";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.
-
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
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.