Terminating a Worker thread from a Parent thread - MFC - multithreading

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;
}

Related

How to cancel a thread from another thread (Glib threads)?

I am developing an application library using GTK and the functions for threads in GLib. I have a thread (from now on will be called thread A) that is created when I hit an "ok" button in a certain graphical window. Thread A starts doing some heavy tasks. Another button named "cancel" is available to stop and finish thread A at any moment.
My aim is to code a function for the thread created when I hit the "cancel" button (thread B) that has the ability to end the thread A.
I create thread A with the function g_thread_create. However I cannot find any function similar to g_thread_cancel to stop thread A using thread B. Is this possible or cannot be done?
Thank you so much for any kind of information provided.
You might want to consider using GTask to run your task in a thread, rather than using a manually-created thread. If you use g_task_run_in_thread(), the operation will run in a separate thread automatically.
GTask is integrated with GCancellable, so to cancel the operation you would call g_cancellable_cancel() in the callback from your ‘Cancel’ button.
As OznOg says, you should treat the GCancellable as a way of gently (and thread-safely) telling your task that it should cancel. Depending on how your long-running task is written, you could either check g_cancellable_is_cancelled() once per loop iteration, or you could add the GSource from g_cancellable_source_new() to a poll loop in your task.
The advice about using threads with GLib is probably also relevant here.
I have developed a code that is able to cancel a thread from another, both of them created from a main one. The code works correctly according to my tests:
#include <pthread.h>
#include <stdio.h>
/* these variables are references to the first and second threads */
pthread_t inc_x_thread, inc_y_thread;
/* this function is run by the first thread */
void *inc_x(void *x_void_ptr)
{
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
/* increment x to 100 */
int *x_ptr = (int *)x_void_ptr;
while(++(*x_ptr) < 100000000);
printf("x increment finished\n");
/* the function must return something - NULL will do */
return NULL;
}
/* this function is run by the second thread */
void *inc_y(void *x_void_ptr)
{
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
/* increment y to 100 */
int *x_ptr = (int *)x_void_ptr;
pthread_cancel(inc_x_thread);
while(++(*x_ptr) < 100);
printf("y increment finished\n");
return NULL;
}
/* this is the main thread */
int main()
{
int x = 0, y = 0;
void *res;
/* show the initial values of x and y */
printf("x: %d, y: %d\n", x, y);
/* create a first thread */
if(pthread_create(&inc_x_thread, NULL, inc_x, &x)) {
fprintf(stderr, "Error creating thread\n");
return 1;
}
/* create a second thread */
if(pthread_create(&inc_y_thread, NULL, inc_y, &y)) {
fprintf(stderr, "Error creating thread\n");
return 1;
}
/* wait for the first thread to finish */
if(pthread_join(inc_x_thread, &res)) {
fprintf(stderr, "Error joining thread\n");
return 2;
}
if (res == PTHREAD_CANCELED)
printf(" thread was canceled\n");
else
printf(" thread wasn't canceled\n");
/* wait for the second thread to finish */
if(pthread_join(inc_y_thread, &res)) {
fprintf(stderr, "Error joining thread\n");
return 2;
}
if (res == PTHREAD_CANCELED)
printf(" thread was canceled\n");
else
printf(" thread wasn't canceled\n");
/* show the results*/
printf("x: %d, y: %d\n", x, y);
return 0;
}
You can compile the code by using: gcc example.c -lpthread
However, as OznOg and Philip Withnall have said, this is not the correct way of cancelling a thread. It is only a quick way of doing it that might not work in some specific situations. A better and safer way is to gently ask the thread to stop itself.

Using SendMessageToDescendants between threads

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(&notificationmessage); // 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(&notificationmessage); // 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(&notificationmessage); // 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.)

Synchronising threads using Events in windows

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.

how to create and update window in child thread using vc++

I just coded a child thread to create and update window but I am facing some problem. My window closes automatically after that thread execution is completed (naturally). But I don't want to close it so I tried putting a while loop in thread and in that loop I am calling InvalidateRect() function so that it can update window. Now window is not closing automatically but i can't move it or interact with it and cursor also showing some busy icon(means completely not responding). How I can solve that problem. below is code:
calling this from main()
bool CameraApp::OnInit()
{
hThread = (HANDLE)_beginthreadex( NULL, 0, &CameraFrame::StartCameraPreview,
NULL, 0, &threadID );
WaitForSingleObject( hThread, INFINITE );
CloseHandle( hThread );
return TRUE;
}
Thread function block
unsigned __stdcall CameraFrame::StartCameraPreview( void* pArgs )
{
cFrame.ShowCameraWindow();
while(1)
{
cFrame.StartCapture();
InvalidateRect(hwnd, NULL, false);
Sleep(5000);
}
_endthreadex( 0 );
return 0;
}
i can't use main() function to create window. So, i have to use thread and update that window with periodic image taken from web-camera.
Instead of your infinite loop you need to create message pump in secondary thread that processes windows messages.
unsigned __stdcall CameraFrame::StartCameraPreview( void* pArgs )
{
cFrame.ShowCameraWindow();
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
_endthreadex( 0 );
return 0;
}

Can't get my thread to execute with SetEvent and WaitForSingleObject

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.

Resources