In my MFC application I have a worker thread that listens on a network connection and as soon as some information has arrived I call SendMessageToDescendants to send that information via the lparam parameter. So every frame window will get the message and possibly process it via a message handler for the WM_SYNCHRONOTIFICATION message (WM_SYNCHRONOTIFICATION is a WM_APP+x message).
Code in the worker thread: (simplified for brevity)
while (TRUE)
{
CNotificationMessage notificationmessage;
Listen(¬ificationmessage); // blocking until some information arrives
m_pMainWnd->SendMessageToDescendants(WM_SYNCHRONOTIFICATION, NULL, (LPARAM)(newnotif));
// have all OnSynchroNotification handlers been called here ?
}
Message handler in the main thread:
LRESULT CMyFrame::OnSynchroNotification(WPARAM p1, LPARAM p2)
{
CNotificationMessage *pNotification = (CNotificationMessage*)p2;
// process message (ommited for brevity)
}
The code works fine, but I'm not sure if upon return from SendMessageToDescendants all OnSynchroNotification have been called.
The simplest solution to use is a counter. Before calling SendMessage, initialize a shared counter to the number of child windows you would like to have process the message. Each message handler is then responsible for decrementing the counter when it completes its work, and your event loop can check that the counter is 0 before generating more events. In pseudo C++:
unsigned int sharedCount; // global/static shared value
while (TRUE)
{
CNotificationMessage notificationmessage;
Listen(¬ificationmessage); // blocking until some information arrives
unsigned int current = InterlockedCompareExchange(&sharedCount, activeWindowCount, 0);
if (current == 0)
{
m_pMainWnd->SendMessageToDescendants(WM_SYNCHRONOTIFICATION, NULL, (LPARAM)(newnotif));
}
else
{
// Still processing the last message.
}
while (InterlockedCompareExchange(&sharedCount, 0, 0) != 0)
{
Sleep(100);
}
}
LRESULT CMyFrame::OnSynchroNotification(WPARAM p1, LPARAM p2)
{
// Processing
InterlockedDecrement(&sharedCount);
}
The slightly more complex solution, but the one I personally prefer, since you don't have to burn CPU waiting on completion, is to create an event for each message processing window, and then use WaitForMultipleObjects (or the Ex version) to halt the event loop until completion. Again, in pseudo C++:
while (TRUE)
{
CNotificationMessage notificationmessage;
Listen(¬ificationmessage); // blocking until some information arrives
m_pMainWnd->SendMessageToDescendants(WM_SYNCHRONOTIFICATION, NULL, (LPARAM)(newnotif));
DWORD waitResult = WaitForMultipleObjects(activeWindowCount, FrameEvents, TRUE, INFINITE);
if (waitResult == WAIT_OBJECT_0)
{
// Success
}
else if (waitResult == WAIT_FAILED)
{
// Failure: Use GetLastError() to figure out why the function call failed.
}
// Reset the events
}
LRESULT CMyFrame::OnSynchroNotification(WPARAM p1, LPARAM p2)
{
// Processing
SetEvent(thisFramesEvent);
}
This example uses an infinite timeout, but you can always set a reasonable timeout, and check for the return value WAIT_TIMEOUT to see if the time elapsed.
(Required Disclaimer: Error checking and variable initialization have been removed from both of these for the sake of brevity and readability. See the documentation for how to check for errors.)
Related
I've just started with learning MFC and I'm writing one dialog based application for better understanding of Multi-Threading.
The main dialog has a progress bar, a Start button and a Cancel button.
On click of the start button, i'm creating a worker thread to do some processing(through API call) and the main thread takes care of Progress bar.
I've defined a couple of Windows Messages to update and stop Progress bar status
WM_UPDATE_CONTROL
WM_STOP_CONTROL
Below is the code that i've created so far
HWND* phObjectHandle;
CWinThread* thread;
void CprogCtrlDlg::OnBnClickedStart() {
phObjectHandle = new HWND; // Set object handle for Worker thread
*phObjectHandle = GetSafeHwnd();
// create worker thread
if(NULL == (thread = AfxBeginThread(ThreadFunc, phObjectHandle))) {
EndDialog(IDCANCEL);
}
AfxMessageBox(L"Thread started");
// Set Progress bar to marquee
}
void CprogCtrlDlg::OnBnClickedCancel() {
// kill the Worker thread
}
UINT CprogCtrlDlg::ThreadFunc(LPVOID pParam) {
HWND *pObjectHandle = static_cast<HWND *>(pParam);
CprogCtrlImpDlg* threadDlg = (CprogCtrlImpDlg*) pParam;
return threadDlg->ThreadFuncRun(pObjectHandle);
}
UINT CprogCtrlDlg::ThreadFuncRun(HWND* pObjectHandle) {
::PostMessage(*pObjectHandle, WM_UPDATE_CONTROL, 0, 0);
// repetitive API CALL in a loop
::PostMessage(*pObjectHandle, WM_STOP_CONTROL, 0, 0);
AfxMessageBox(L"Thread completed");
return 0;
}
I want to terminate the Worker thread from a Parent thread, if a Cancel button is clicked.
I tried using TerminateThread()(though it wasn't a suggested one) but I couldn't kill the thread.
Please comment and share your thoughts on terminating a worker thread from a parent thread.
I'm using visual studio 2010 on Windows 7
TIA
I would amend your code something like this.
Have some member variables in your dialog class to hold the thread handle and an event handle (initialise to NULL in the constructor):
CWinThread* m_hThread;
HANDLE m_hKillEvent;
Use a static function as your thread entry point, pass the dialog this as the parameter, then delegate the call back to the class instance so you have access to all of the dialog's variables:
UINT ThreadFunc(LPVOID pParam)
{
// static thread func - delegate to instance
CprogCtrlDlg* pDlg = static_cast<CprogCtrlDlg*>(pParam);
return pDlg->ThreadFuncRun();
}
When you start the thread, create an event too:
void CprogCtrlDlg::OnBnClickedStart()
{
// create worker thread
m_hKillEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
m_hThread = AfxBeginThread(ThreadFunc, this);
AfxMessageBox(L"Thread started");
}
To kill the thread, just set the event and wait on the thread handle, which will get signaled on death:
void CprogCtrlDlg::OnBnClickedCancel()
{
// kill the Worker thread
SetEvent(m_hKillEvent);
// wait for it to die
DWORD dwRet = WaitForSingleObject(m_hThread->m_hThread, 5000);
if (dwRet == WAIT_TIMEOUT)
{
// thread failed to die after 5 seconds
// error handling (maybe TerminateThread here)
}
}
In the thread function (now in the dialog class) you can post messages to yourself to indicate progress and use a wait on the event to catch a kill request:
UINT CprogCtrlDlg::ThreadFuncRun()
{
// instance thread func
PostMessage(WM_UPDATE_CONTROL, 0, 0);
// main loop
while (true)
{
// check kill
DWORD dwRet = WaitForSingleObject(m_hKillEvent, 0);
if (dwRet == WAIT_OBJECT_0) break;
// do a little work here and update progress
// ... so this is part of your working loop ...
PostMessage(WM_UPDATE_CONTROL, 0, 1 /*2,3,4,...*/);
}
// normal thread exit
PostMessage(WM_STOP_CONTROL, 0, 0);
return 0;
}
I've left out initialisation, cleanup of pointers, handles etc. but you get the general idea I hope.
There are several ways you can code the thread loop, you can do it like above where you periodically check to see if the event is signaled, or you can wait on the event to get signaled to do the work. Both are common patterns and often used together with two events - one for triggering work and the other for killing. See this answer for some important points to note if waiting on multiple events.
For a simple progress bar update, you can put the event check inside the work loop, something like this:
UINT CprogCtrlDlg::ThreadFuncRun()
{
// instance thread func
PostMessage(WM_UPDATE_CONTROL, 0, 0);
// main loop
for (int i = 0; i < 100; ++i)
{
// check kill
DWORD dwRet = WaitForSingleObject(m_hKillEvent, 0);
if (dwRet == WAIT_OBJECT_0) break;
// do a little work here and update progress
PostMessage(WM_UPDATE_CONTROL, 0, (LPARAM)i);
}
// normal thread exit
PostMessage(WM_STOP_CONTROL, 0, 0);
return 0;
}
I have a project in Visual C++ 2010 where I have to draw some circles and lines. The coordinates of the circles depend on two global variables. The global variables are modified from two functions, each running in their own thread. Boost is used for multi-threading.
However, as soon as I run the threads, my main thread is blocked, thus preventing me from drawing the shapes and using the global variables. How can I get around this? What I ultimately want to achieve is, modify the global variables from two seperate functions running in their own thread and simultaneously draw the circles using the said global varibales
global_variable_1
global_variable_2
void function_1()
{
while(true)
{
//modifies global_variable_1
}
}
void function_2()
{
while(true)
{
//modifies global_variable_2
}
}
void MyOnPaint(HDC hdc)
{
Graphics graphics(hdc);
Pen pen(Color::Blue);
/* Uses global_variable_1 & global_variable_2 to
draw circles */
}
int APIENTRY _tWinMain(......)
{
/* Some initial code */
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_GAZEPOINTEVALUATION));
/*Start threads*/
using namespace boost;
thread thread_1(function_1);
thread thread_2(function_2);
//Start threads
thread_1.join()
thread_2.join()
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
/* Some code */
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
/*CALL MY DRAWING METHOD*/
MyOnPaint(hdc);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
/* Some code */
default:
/* Some code */
}
return 0;
}
join calls will never return because your threads loop for ever. From the docs:
In order to wait for a thread of execution to finish, the join(),
__join_for or __join_until ( timed_join() deprecated) member functions of the boost::thread object must be used. join() will block the
calling thread until the thread represented by the boost::thread
object has completed.
You never enter your message loop, therefore.
If you remove the join calls, this should do something more like what you expect - in a more complex application you'd need to properly design thread scheduling and exit handling. Even as it stands, you will likely have to add some delay into the spawned threads to avoid pegging the CPU and possibly seeing other weirdness you are not expecting.
I Read a few threads on how passing data from Workerthread to Main window(Dialog), but I still don't understand and still need help.
My workerthread should process some calculations and display the result during each loop to an edit on the GUI. I know, I should use PostMessage but since the calculation I'm doing implies a control element, I don't know how to solve this problem ...
//CWorkerThreadMgr.h manages the second thread
HRESULT Start (HWND hWnd);// from where the workerthread will be started
HWND m_hWnd ; //Window handle to the UI ;
HANDLE m_hTread; //handle of the worker thread
static UINT WINAPI ThreadProc( LPVOID lptest );
static UINT WINAPI ThreadProc( LPVOID lptest )
{
CWorkerThreadMgr* pCalculateMgr = reinterpret_cast< CWorkerThreadMgr*(lptest);
//The following operation:rand() *m_Slider.GetPos() should
//should be calculated and the result displayed each time in the edit box in the gui
for( UINT uCount = 0; uCount < 40; uCount++ ){
pCalculateMgr->rand() *m_Slider.GetPos();//?don't allowed to touch the gui!!
PostMessage(pCalculateMgr-> m_hWnd, WM_SENDCALCULATED_VALUE,wparam(rand() *m_Slider.GetPos(),0);
}
}
LRESULT CStartCalculationDlg::OnSendCalculatedValue( WPARAM Result, LPARAM )
{
// The resut should be displayed in the edit box
m_Calculation.Format(_T("%d"),???);
SetDlgItemText(IDC_CALCULATION, m_Calculation);
return 1;
}
void CStartCalculationDlg::OnHScroll(UINT nSBCode, UINT nPos,CScrollBar* pScrollBar)
{
m_SliderValue.Format(_T("%d"),m_Slider.GetPos());
SetDlgItemText(IDC_SLIDER_VALUE,m_SliderValue);
}
// Implementation in the CStartCalculationDlg.h
CWorkerThreadMgr m_WorkerThreadMgr //instance of the WorkerThreadMgr
CSliderCtrl m_Slider //member variable of the slider control
CString m_SliderValue // member variable of the edit box, where the current value of the
//slider will be displayed
CString m_Calculation // member variable of the edit box where the calculated
//result from the workerthread will be displayed via PostMessage
afx_msg LRESULT OnSendCalculatedValue( WPARAM, LPARAM );
afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
The next probem is that, when my slider control is moved and gets a new value, the thread procedure should know it and update the value of the slider. How can I manage to do it?
Instead of reading the slider position from the worker thread, read it in the UI thread and make it available to the worker thread.
I'm really no expert in this field, but I've done some worker threads as explained here.
What I would do in your case is create a static variable, like the "running" flag used in the article linked above, to hold the current position of the slider. Then, in the OnHScroll handler set it to the appropriate value.
As long as you only write to that variable from one thread, you should not have synchronization issues.
From worker thread:
m_data = foo();
PostMessage(hWndMain, UWM_SOME_CUSTOM_MESSAGE, 0, 0);
From UI thread:
LRESULT CMainFrame::OnSomeCustomMessage(WPARAM wParam, LPARAM lParam)
{
CMyData data = m_pWorker->GetData();
// Do stuff...
return 0;
}
GetData must be guarded by a critical section:
CMyData CMyWorker::GetData()
{
// This critical section is used in the worker thread too, whenever m_data is accessed.
m_lock.Lock();
CMyData data = m_data;
m_lock.Unlock();
return data;
}
See CCriticalSection on MSDN.
I need to synchronize threads using events. First I am not getting concept of Events in windows. I will take an example, I have main thread and secondary thread. I created a two events called "write" and "test". In main thread I signaled for 'write" event and waited on the "test" event. Both the events are getting signaled.
Basically I am porting an appli from linux to windows. The linux program uses condition variable to signaling the thread. Condition variable is not available in window XP.
Ex:
#include <windows.h>
#include <stdio.h>
#define THREADCOUNT 1
HANDLE ghWriteEvent;
HANDLE ghtestEvent;
HANDLE ghThreads[THREADCOUNT];
DWORD WINAPI ThreadProc(LPVOID);
void CreateEventsAndThreads(void)
{
int i;
DWORD dwThreadID;
ghWriteEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // initial state is nonsignaled
TEXT("WriteEvent") // object name
);
if (ghWriteEvent == NULL)
{
printf("CreateEvent failed (%d)\n", GetLastError());
return;
}
ghtestEvent = CreateEvent(
NULL, // default security attributes
FALSE, // manual-reset event
FALSE, // initial state is nonsignaled
TEXT("WriteEvent") // object name
);
if (ghtestEvent == NULL)
{
printf("CreateEvent failed (%d)\n", GetLastError());
return;
}
// Create multiple threads to read from the buffer.
for(i = 0; i < THREADCOUNT; i++)
{
// TODO: More complex scenarios may require use of a parameter
// to the thread procedure, such as an event per thread to
// be used for synchronization.
ghThreads[i] = CreateThread(
NULL, // default security
0, // default stack size
ThreadProc, // name of the thread function
NULL, // no thread parameters
0, // default startup flags
&dwThreadID);
if (ghThreads[i] == NULL)
{
printf("CreateThread failed (%d)\n", GetLastError());
return;
}
}
}
void WriteToBuffer(VOID)
{
DWORD dwWaitResult;
printf("Main thread writing to the shared buffer...\n");
printf("Posting Events for %d\n",ghWriteEvent );
// Set ghWriteEvent to signaled
if (! SetEvent(ghWriteEvent) )
{
printf("SetEvent failed (%d)\n", GetLastError());
return;
}
dwWaitResult= WaitForSingleObject(
ghtestEvent, // event handle
INFINITE); // indefinite wait
printf("WaitForSingleObject signelled (%d)\n", GetLastError());
if ( dwWaitResult == WAIT_OBJECT_0)
printf("Signlled State for %d with ret val : %d\n",ghtestEvent,dwWaitResult );
}
void CloseEvents()
{
// Close all event handles (currently, only one global handle).
CloseHandle(ghWriteEvent);
}
int main( void )
{
DWORD dwWaitResult;
CreateEventsAndThreads();
WriteToBuffer();
printf("Main thread waiting for threads to exit...\n");
// The handle for each thread is signaled when the thread is
// terminated.
dwWaitResult = WaitForMultipleObjects(
THREADCOUNT, // number of handles in array
ghThreads, // array of thread handles
TRUE, // wait until all are signaled
INFINITE);
switch (dwWaitResult)
{
// All thread objects were signaled
case WAIT_OBJECT_0:
printf("All threads ended, cleaning up for application exit...\n");
break;
// An error occurred
default:
printf("WaitForMultipleObjects failed (%d)\n", GetLastError());
return 1;
}
// Close the events to clean up
CloseEvents();
return 0;
}
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
// lpParam not used in this example.
UNREFERENCED_PARAMETER(lpParam);
DWORD dwWaitResult;
printf("Thread %d waiting for write event...\n", GetCurrentThreadId());
dwWaitResult = WaitForSingleObject(
ghWriteEvent, // event handle
INFINITE); // indefinite wait
printf("rcvd event for Write is %d \n", ghWriteEvent);
switch (dwWaitResult)
{
// Event object was signaled
case WAIT_OBJECT_0:
WaitForSingleObject(
ghtestEvent, // event handle
INFINITE); // indefinite wait
printf("rcvd event for %d with Error %d\n", ghtestEvent,GetLastError());
if ( dwWaitResult == WAIT_OBJECT_0)
{
printf("Test event signaled for second thread \n");
}
break;
// An error occurred
default:
printf("Wait error (%d)\n", GetLastError());
printf("Wait error (%d)\n", GetLastError());
return 0;
}
printf("Thread %d exiting\n", GetCurrentThreadId());
return 1;
}
Output of the program is:
Main thread writing to the shared buffer...
Posting Events for 2012
WaitForSingleObject signelled (183)
Signlled State for 2008 with ret val : 0
Main thread waiting for threads to exit...
Thread 2016 waiting for write event...
rcvd event for Write is 2012
rcvd event for 2008 with Error 0
Test event signaled for second thread
Thread 2016 exiting
All threads ended, cleaning up for application exit...
After a long struggle I found out the reason. If Two events are created with same Name, the second event while creating will throw an Error "ERROR_ALREADY_EXISTS (183).
If event are created with different name, it works without any issue. It is good programming to check the error and proceed accordingly.
ghtestEvent = CreateEvent(
NULL, // default security attributes
FALSE, // manual-reset event
FALSE, // initial state is nonsignaled
TEXT("WriteEvent") // object name
);
if ( ERROR_ALREADY_EXISTS == GetLastError() )
{
printf("unable to create event (%d)\n".GetLastError());
exit(0);
}
Regards
JOhnnie
You only need to name events if you're going to use them to communicate between processes. You can pass NULL as the name if you're only synchronization threads within a single process.
When I'm creating named synchronization objects for inter-process communication, I generally give them a descriptive name (like "MyCompany - MyApp - WriteEvent") and tack on a GUID for good measure. You don't want to have a name conflict with some other developer who named his event "WriteEvent". The name can be up to MAX_PATH characters long and there is no performance penalty.
I'm trying to create a thread and let it run until my main signals it to start, which I think is done with SetEvent. But the code in the thread is never executed. Below is the bare code I have stripped down of (I think) unrelated functions. Is the algorithm correct ?
Here is what I thought it did :
When in the main, the thread is created, which means it'll run in the background. When the event is set (SetEvent), the thread picks it up at WaitForSingleObject and then execute the code in the thread, right ?
HANDLE hThread;
HANDLE Event;
DWORD Thread()
{
while(1)
{
wait = WaitForSingleObject(Event, INFINITE)
//This is where I want to execute something
}
}
int _tmain()
{
DWORD dw;
int i;
Event = CreateEvent(NULL,false,false,NULL);
hThread = CreateThread(NULL,0,Thread,EventA,0,NULL);
while(1)
{
if (condition is correct)
{
SetEvent(Event);
}
CloseHandle(Thread);
CloseHandle(Event);
}
return 0;
}
Thanks for having read.
Move CloseHandle lines out of the while loop.