I have a thread that does lengthy processing. While I am waiting for the thread to finish, I kick start another 'show progress' thread which simply toggles a bitmap back and forth to show program is crunching on data. To my surprise this approached didn't work at all.
My 'show progerss' thread simply stop updating (=running) when the main activity starts and it starts updating when that activity ends. This is nearly the oppose of what I want! Should I expect this behavior because of the WaitForSingleOBjectwhich is in wait state for most of the time and wakes up briefly?
// This is the main thread that does the actual work
CWinThread* thread = AfxBeginThread(threadDoWork, this, THREAD_PRIORITY_LOWEST, 0, CREATE_SUSPENDED );
thread->m_bAutoDelete = FALSE;
thread->ResumeThread();
// before I start to wait on the above thread, I start this thread which will toggle image to show application is processing
AfxBeginThread(ProgressUpdateThread, &thread_struct_param, THREAD_PRIORITY_NORMAL, 0 );
// wait for the main thread now.
DWORD dwWaitResult = WaitForSingleObject( thread->m_hThread, INFINITE );
DWORD exitCode;
::GetExitCodeThread( thread->m_hThread, &exitCode );
delete thread;
// This thread toggles image to show activity
UINT ProgressUpdateThread(LPVOID param)
{
CEvent * exitEvent = ((mystruct *)param)->exitEvent;
MyView *view ((mystruct *)param)->view;
int picture = 0;
do
{
waitResult = WaitForSingleObject( exitEvent->m_hObject, 100);
if (waitResult == WAIT_TIMEOUT)
{
picture = toggle ? 1: 0;
// invert
toggle = !toggle;
View->Notify( UPDATE_IMAGE, picture );
}
else if (waitResult == WAIT_OBJECT_0)
{
return TRUE;
}
}
while( 1);
}
Another consideration in my solution is that I would like to not touch the actual 'DoWork' thread code and that's also why I am using separate thread to update GUI. Can I make this approach work? Is the only way to update GUI reliable is to update it from the actual 'DoWork thread itself?
I do want to clarify that my 'Show progress' thread does the job perfectly if the application is idle, but if I launch the worker thread operation (in lower thread priority), the update gui thread simply stops running and resume only when the worker finishes.
I am using Windows 7.
Your design is all wrong and over-complicated for what you are attempting. Try something more like this simpler solution:
bool toggle = false;
VOID CALLBACK updateProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
int picture = toggle ? 1: 0;
toggle = !toggle;
View->Notify( UPDATE_IMAGE, picture );
}
CWinThread* thread = AfxBeginThread(threadDoWork, this, THREAD_PRIORITY_LOWEST, 0, CREATE_SUSPENDED );
thread->m_bAutoDelete = FALSE;
thread->ResumeThread();
UINT_PTR updateTimer = SetTimer(NULL, 0, 100, updateProc);
do
{
DWORD dwWaitResult = MsgWaitForMultipleObjects(1, &(thread->m_hThread), FALSE, INFINITE, QS_ALLINPUT );
if (dwWaitResult == WAIT_OBJECT_0)
break;
if (dwWaitResult == (WAIT_OBJECT_0+1))
{
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
while (true);
KillTimer(NULL, updateTimer);
DWORD exitCode;
::GetExitCodeThread( thread->m_hThread, &exitCode );
delete thread;
If you do not want to use a standalone procedure for the timer, you can adjust the parameters of SetTimer() to have it post WM_TIMER messages to an HWND of your choosing instead, and then do the UI updates in that window's message procedure as needed. You would still need the message loop to pump the timer messages, though.
The alternative is to simply not do any waiting at all. Once you start the worker thread, move on to other things, and let the worker thread notify the main UI thread when it is done with its work.
Remy Lebeau pointed out correctly that my main GUI thread was actually waiting on the worker thread. Now since my worker gui-update thread was (obviously) calling gui function, it was in turn blocked on main GUI thread. I realized even SetWindowText() from a third thread will put that thread in wait if the main GUI thread is in wait or blocked state.
I don't like to use PeekandPump() mechanism, I thought it was a bad design smell. It was originally used in early windows (before win95 I think) which were not truly multitasking. To the best of my knowledge this should not be used now.
My solution was to put the whole code that I posted in OP in a new thread. So my button click in gui creates this threat and returns immediately. This master worker thread can now wait on other threads and my GUI will never block. When it gets completed, it post a message to the parent window to notify it. The bitmap is now changed perfectly using a separate gui-update thread when the application is processing in another thread.
Related
I'm trying to learn WTL / Win32 programming, and I don't quite understand the design of the CIdleHandler mixin class.
For WTL 9.1, The CMessageLoop code is as follows (from atlapp.h):
for(;;)
{
while(bDoIdle && !::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE))
{
if(!OnIdle(nIdleCount++))
bDoIdle = FALSE;
}
bRet = ::GetMessage(&m_msg, NULL, 0, 0);
if(bRet == -1)
{
ATLTRACE2(atlTraceUI, 0, _T("::GetMessage returned -1 (error)\n"));
continue; // error, don't process
}
else if(!bRet)
{
ATLTRACE2(atlTraceUI, 0, _T("CMessageLoop::Run - exiting\n"));
break; // WM_QUIT, exit message loop
}
if(!PreTranslateMessage(&m_msg))
{
::TranslateMessage(&m_msg);
::DispatchMessage(&m_msg);
}
if(IsIdleMessage(&m_msg))
{
bDoIdle = TRUE;
nIdleCount = 0;
}
}
The actual call to idle handlers is very straightforward.
// override to change idle processing
virtual BOOL OnIdle(int /*nIdleCount*/)
{
for(int i = 0; i < m_aIdleHandler.GetSize(); i++)
{
CIdleHandler* pIdleHandler = m_aIdleHandler[i];
if(pIdleHandler != NULL)
pIdleHandler->OnIdle();
}
return FALSE; // don't continue
}
As is the call to IsIdleMessage
static BOOL IsIdleMessage(MSG* pMsg)
{
// These messages should NOT cause idle processing
switch(pMsg->message)
{
case WM_MOUSEMOVE:
#ifndef _WIN32_WCE
case WM_NCMOUSEMOVE:
#endif // !_WIN32_WCE
case WM_PAINT:
case 0x0118: // WM_SYSTIMER (caret blink)
return FALSE;
}
return TRUE;
}
My analysis is as follows: it seems like once per "PeekMessage Drought" (a period of time where no messages are sent to the Win32 Application), the OnIdle handlers are called.
But why just once? Wouldn't you want background idle tasks to continuously be called over and over again in the case when PeekMessage ? Furthermore, it seems strange to me that WM_LBUTTONDOWN (User has left-clicked something on the Window) would activate idle processing (bDoIdle = True), but WM_MOUSEMOVE is explicitly called out to prevent reactivation of idle processing.
Can anyone give me the "proper" use scenario of WTL Idle Loops (or more specifically: CIdleHandler)? I guess my expectation was that Idle-processing functions would be small, incremental tasks that take no more than say... 100ms to complete. And then they'd be called repeatedly in the background.
But it seems like this is not the case in WTL. Or maybe I'm not fully understanding Idle loops? Because if I had an incremental background task registered as a CIdleHandler... then if the user stepped away from the window, the task would get run only once! Without any messages pumped into the system (such as WM_LBUTTONDOWN), the bDoIdle variable would remain false for all time!
Does anyone have a good explanation for all this?
As said in the comments, OnIdle handler is supposed to be called when idling starts after certain activity, esp. in order to update UI. This explains "once" calling of the handlers: something happened and then you have a chance to once update the UI elements. If you need ongoing background processing, you are supposed to use timers or worker threads.
WTL samples suggest the use of idle handlers, e.g. in \Samples\Alpha\mainfrm.h.
Window class picks up message loop of the thread and requests idleness updates:
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
// ...
// register object for message filtering and idle updates
CMessageLoop* pLoop = _Module.GetMessageLoop();
ATLASSERT(pLoop != NULL);
pLoop->AddMessageFilter(this);
pLoop->AddIdleHandler(this);
Later on after message processing and user interaction, the idleness handler updates toolbar to reflect possible state changes:
virtual BOOL OnIdle()
{
UIUpdateToolBar();
return FALSE;
}
I have a DLL which has a CWinThread based class called CWork.
I create it using AfxBeginThread.
In this class I defined a procedure that will loop infinetly and perform a certain task. This procedure will be used as a thread by itself. I create it also using AfxBeginThread.
Now, when my DLL exits, I'd like to end the thread. This is because I have a crash on exit, and I am affraid that is the reason.
In addition, there is
Pseudo Code example:
class Cmain
Cmain::Cmain(){
pMyThread = AfxBeginThread(CWork - a CWinThread based Class);
}
UINT HandleNextVTSConnectionCommandProc(LPVOID pParam);
class CWork
CWork:CWork(){
AfxBeginThread(HandleNextVTSConnectionCommandProc, this);
}
UINT HandleNextVTSConnectionCommandProc(LPVOID pParam){
while(true){
dosomething();
sleep(2000);
}
}
My question is, what is the correct way of ending those 2 threads?
Thank you!
In general the correct way to end a thread is to ask it to finish and then wait for it to do so. So on Windows you might signal an event to ask the thread to finish up then wait on the thread HANDLE. Forcefully terminating a thread is almost always a misguided idea which will come back to haunt you.
Create an event calling CreateEvent that is initially non-signaled. When your application terminates, signal this event (SetEvent) and wait for the thread to terminate (WaitForSingleObject on the thread handle).
Inside your thread function HandleNextVTSConnectionCommandProc replace your while(true) loop with
while(WaitForSingleObject(hEvent, 0) != WAIT_OBJECT_0)
Doing the above allows you to signal the thread to terminate from your application. The thread terminates, when it returns from its thread proc.
Set a flag instead of using while(true) to tell your thread when it should end. You could also use an event.
You should also wait for your thread to be complete before you exit, so you should use (in the main code, once you signal the thread to end):
WaitForSingleObject(thread_handle)
Something like this should get you started:
HANDLE g_hThreadExitRequest = NULL;
UINT __cdecl ThreadFunction(LPVOID pParam)
{
AllocConsole();
HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE);
for (int i=1; true; ++i)
{
CStringA count;
count.Format("%d\n", i);
WriteFile(hCon, (LPCSTR)count, count.GetLength(), NULL, NULL);
if (WaitForSingleObject(g_hThreadExitRequest, 1000) == WAIT_OBJECT_0)
break;
}
// We can do any thread specific cleanup here.
FreeConsole();
return 0;
}
void Go()
{
// Create the event we use the request the thread exit.
g_hThreadExitRequest = CreateEvent(
NULL, // LPSECURITY_ATTRIBUTES lpEventAttributes
TRUE, // BOOL bManualReset
FALSE, // BOOL bInitialState
NULL // LPCTSTR lpName
);
// We create the thread suspended so we can mess with the returned CWinThread without
// MFC auto deleting it when the thread finishes.
CWinThread *pThread = AfxBeginThread(
&ThreadFunction, // AFX_THREADPROC pfnThreadProc
NULL, // LPVOID pParam
THREAD_PRIORITY_NORMAL, // int nPriority
0, // UINT nStackSize
CREATE_SUSPENDED , // DWORD dwCreateFlags
NULL // LPSECURITY_ATTRIBUTES lpSecurityAttrs
);
// Turn off MFC's auto delete "feature".
pThread->m_bAutoDelete = FALSE;
// Start the thread running.
pThread->ResumeThread();
// Wait 30 seconds.
Sleep(30*1000);
// Signal the thread to exit and wait for it to do so.
SetEvent(g_hThreadExitRequest);
WaitForSingleObject(pThread->m_hThread, INFINITE);
// Delete the CWinTread object since we turned off auto delete.
delete pThread;
// We're finished with the event.
CloseHandle(g_hThreadExitRequest);
g_hThreadExitRequest = NULL;
}
I have set an int variable for the "EditBox" control in c++/mfc. now I want to change its value in a thread.
I define a thread like the bellow :
CWinThread *pThread();
UINT FunctionThread(CthDlg& d)
{
DWORD result = 0;
int i = 0;
while (1)
{
if (i == 5000) i = 0;
d.m_text1 = i;
i++;
d.UpdateData(FALSE);
}
return result;
}
void CthDlg::OnBnClickedOk()
{
// TODO: Add your control notification handler code here
pThread = AfxBeginThread(FunctionThread, THREAD_PRIORITY_NORMAL);
}
Where's the Problem?
You should run your code in debug mode and under the debugger, then you would see that you get an assertion.
The problem is that MFC only allows access to a window from the thread that created the window. In your case that means that the main thread can access the windows, but the worker thread can not. UpdateData is accessing the windows, so this does not work in a worker thread.
So what you need to do is signal from the worker thread to the main thread that a new value is available and shall be displayed. For that signaling you can post a window message to the dialog window (PostMessage). Be sure not to use SendMessage because this will block until the message is received. You might run into a dead lock if the main thread is waiting for the worker thread and the worker thread is waiting for the main thread in SendMessage. When the main thread receives the message it can update the window control.
BTW, your code is not valid. AfxBeginThread requires a AFX_THREADPROC which is declared as UINT __cdecl MyControllingFunction(LPVOID pParam);. You need to change your thread function to
UINT __cdecl FunctionThread(LPVOID pParam)
{
CthDlg& d = *reinterpret_cast<CthDlg*>(pParam);
I think i am ruining in to a deadlock, have been searching for the solution over hours. Any suggestions?
What i am trying to do is: ater startGame button click, create thread that send request to the server and then gets the answer, after the answer the thread must send a message to Initialize game window to the main proc...
Message Proc that belongs to WinMain:
LRESULT CALLBACK WndProc(HWND myWindow, UINT messg, WPARAM wParam, LPARAM lParam)
{
switch (messg) {
case WM_STARTGAME:
DestroyWindow(hStartGameButton);
DestroyWindow(hHistoryButton);
InitGameWindow(myWindow);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_STARTGAME_BUTTON:
{
parametros param;
param.myWindow = myWindow;
start_game = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadStartGame, (LPVOID)&myWindow, 0, NULL);
}
}
}
And this is the thread:
DWORD WINAPI ThreadStartGame(LPVOID param){
HWND w = (HWND)param;
DWORD n;
BOOL ret;
mensagem resposta;
mensagem msg;
msg.tipo = COMECAR_JOGO;
msg.verifica = true;
if (!WriteFile(hPipe, &msg, (DWORD)sizeof(mensagem), &n, NULL)) {return 0;}
ret = ReadFile(hPipeN, &resposta, (DWORD)sizeof(mensagem), &n, NULL);
if (!ret || !n) {
return false;
}
PostMessage(w, WM_STARTGAME, NULL, NULL); // <- THIS GETS EXECUTED BUT NOTHINK HAPPENS AFTER
return 0;
}
I don't think there is any deadlock here.
start_game = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadStartGame, (LPVOID)&myWindow, 0, NULL);
This line passes the address of the HWND to the thread (&myWindow)
HWND w = (HWND)param;
This line uses the adress itself as HWND and the SendMessage sends the message to this address which is not a HWND.
Try modifying to
start_game = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadStartGame, (LPVOID)myWindow, 0, NULL);
W/o even looking at the code, I can tell you right away: do not use SendMessage between threads. I recommend reading Psychic debugging: The first step in diagnosing a deadlock is a simple matter of following the money and Preventing Hangs in Windows Applications:
Use asynchronous window message APIs in your UI thread, especially by replacing SendMessage with one of its non-blocking peers: PostMessage, SendNotifyMessage, or SendMessageCallback
...
Any blocking call that crosses thread boundaries has synchronization properties that can result in a deadlock. The calling thread performs an operation with 'acquire' semantics and cannot unblock until the target thread 'releases' that call. Quite a few User32 functions (for example SendMessage), as well as many blocking COM calls fall into this category.
For starters, you're unlikely supposed to do that in the first place. Quoting MSDN:
A thread in an executable that calls the C run-time library (CRT) should use the _beginthreadex and _endthreadex functions for thread management rather than CreateThread and ExitThread; this requires the use of the multithreaded version of the CRT. If a thread created using CreateThread calls the CRT, the CRT may terminate the process in low-memory conditions.
Second, your thread can be worker or UI thread, from the first type you must not call most of the window related functions, as it has no message pump. DestroyWindow is such. (So many times I tried to use MessageBox despite my own comment a few lines upper telling it's forbidden in that function ;).
From worker threads the usual method is to use PostThreadMessage and react on the UI thread. (If you have multiple UI threads, I don't know the rules, was never brave enough for that.)
Here is the issue that I have in c++ code implementation.
In the main thread , created a dialogbox showing static text with cancel button which also spins a child thread.
In the back ground thread ( or the child thread) check the database to see if the certain status field is updated. If updated, then return true, otherwise continue to poll the database at regular intervals.
Expected behavior - Show dialog box with cancel button , continue showing it until the event is signaled by child thread or the user hits cancel button.
I created an event in the main thread with unsignalled state , this event state will be modified by the child tread ( when the status field is updated ).
The problem is if i block the main thread until it gets response from the background thread, the user cannot hit the cancel button in the dialog , it is always accompanied with hour glass symbol.
Not sure what is wrong with the below code.
HANDLE mainThread = NULL;
HANDLE ghWriteEvent;
MainMethod()
{
mainThread = GetCurrentThread() ;
dlgCancelDialog dog // dialog with cancel button .
ghWriteEvent = CreateEvent( NULL, TRUE, FALSE, TEXT("WriteEvent") );
HANDLE hThread = CreateThread(0,0, childThread, &threadData,0,NULL);
dlg.showDialog(); // Show dialog with cancel button .
DWORD dwWaitResult = WaitForSingleObject( ghWriteEvent, INFINITE);
//AT THIS POINT i WANT TO SAY WAIT FOR SIGNAL EVENT OR WAIT UNTIL CANCEL OPERATION IS HIT , BUT THE DIALOG IS SHOWN WITH HOURGLASS SYMBOL.
switch (dwWaitResult)
{
// Event object was signaled
case WAIT_OBJECT_0:
break;
}
dlg.hideDialog();
}
//Child thread code.
childThread(LPVOID lpParam)
{
while(!databaseIsUpdated) // Check database.
{
Sleep(1000);
}
if (! SetEvent(ghWriteEvent) )
{
return 0;
}
return 0;
}
You should not wait with INFINITE because you block your dialog thread.
So my proposal is, create timer using SetTimer(hDlg, 500, 1, NULL) and handle WM_TIMER inside DlgProc like this:
case WM_TIMER:
{
DWORD dwWaitResult = WaitForSingleObject( ghWriteEvent, 0); //We will not wait
if(dwWaitResult == WAIT_OBJECT_0) //We are signaled, exit now
dlg.hideDialog();
}
break;
This will check every 500ms state of event.If signaled, dialog ends, if not, continue.
You could also use MsgWaitForMultipleObjectsEx() : http://msdn.microsoft.com/en-us/library/windows/desktop/ms684245%28v=vs.85%29.aspx