Solved

How to wait for windows c++  threads to terminate?

Posted on 2008-06-11
7
3,148 Views
Last Modified: 2008-06-13
Hi,

I am running into problems regarding threading during termination of a c++ console app.


In my main(), I create an object that, itself, launches many threads. The object, called "commGuy" is of type "MultThreadedCommunicator". When I eventually delete this object, some of the threads that it has launched have not yet completed. The result is a mess.  What I need is a way to wait until all of its threads terminate before I call delete.

The following code illustrates my problem:

Please do not suggest a solution that involves instancing a MultiThreadedCommunicator object directly. For my purposes, it must be referenced only via a pointer obtained by "new".

Thanks!

Kevin
int main()
{
 
	// instance commGuy
	MultiThreadedCommunicator* commGuy = new MultiThreadedCommunicator;
 
	// do a bunch of stuf
	.
	.
	.
 
	// it is now time to terminate the program
 
	// need some code here that waits until commGuy's threads
	// terminate before further program execution occurs
 
 
	// delete commGuy
	delete commGuy;
 
}

Open in new window

0
Comment
Question by:highqllc
  • 4
  • 2
7 Comments
 
LVL 40

Accepted Solution

by:
evilrix earned 250 total points
ID: 21759453
You'll need to use a x-thread communication mechanism, such as an event, to signal the thread(s), you then use WaitForSingleObject or WaitForMultipleObjects to wait for them to finish.

http://msdn.microsoft.com/en-us/library/aa915075.aspx
http://msdn.microsoft.com/en-us/library/ms687032.aspx
http://msdn.microsoft.com/en-us/library/ms687025.aspx
0
 

Author Comment

by:highqllc
ID: 21759482
evilrix,

I forgot to mention that I create threads with _beginthreadex().  The solution you provided seems to be for CreateThread().  Will it also work for _beginthreadex()?
0
 
LVL 40

Expert Comment

by:evilrix
ID: 21759740
>> I forgot to mention that I create threads with _beginthreadex().  The solution you provided seems to be for CreateThread().  Will it also work for _beginthreadex()?

Hmmm... the problem is you need to wait of the thread handle -- I don't believe you get this from beginthreadex().

The only other way I can think of is to give each thread an event it can signal to let the main thread know when it's done, so rather than waiting on the handle you wait on the event. So, each thread has 2 events, one it monitors to see when it's being requested to terminate and another that it then sets as the last thing it does before it terminates to let the main thread know it's done. The main thread sets the event for the thread to tell it to stop and then waits on the other event to signal back when it's done. Its like me telling you to stop and you shouting back when you have.

Does that make sense?
0
Ransomware: The New Cyber Threat & How to Stop It

This infographic explains ransomware, type of malware that blocks access to your files or your systems and holds them hostage until a ransom is paid. It also examines the different types of ransomware and explains what you can do to thwart this sinister online threat.  

 
LVL 86

Assisted Solution

by:jkr
jkr earned 250 total points
ID: 21761418
'_beginthreadex()' returns a thread handle, 'disguised' as a 'unsigned long' - just cast it (code taken from http://msdn.microsoft.com/en-us/library/ms235302(VS.80).aspx - "Multithreading and Locales", coincidentially that one applies exactly to your problem):
// multithread_locale_1.cpp
// compile with: /EHsc /MD
#include <clocale>
#include <cstdio>
#include <locale>
#include <process.h>
#include <windows.h>
 
#define NUM_THREADS 2
using namespace std;
 
unsigned __stdcall RunThreadA(void *params);
unsigned __stdcall RunThreadB(void *params);
 
BOOL localeSet = FALSE;
HANDLE printMutex = CreateMutex(NULL, FALSE, NULL);
 
int main()
{
    HANDLE threads[NUM_THREADS];
 
    unsigned aID;
    threads[0] = (HANDLE)_beginthreadex(
        NULL, 0, RunThreadA, NULL, 0, &aID);
 
    unsigned bID;
    threads[1] = (HANDLE)_beginthreadex(
        NULL, 0, RunThreadB, NULL, 0, &bID);
 
    WaitForMultipleObjects(2, threads, TRUE, INFINITE);
 
    printf_s("[Thread main] Per-thread locale is NOT enabled.\n");
    printf_s("[Thread main] CRT locale is set to \"%s\"\n",
        setlocale(LC_ALL, NULL));
    printf_s("[Thread main] locale::global is set to \"%s\"\n",
        locale().name().c_str());
 
    CloseHandle(threads[0]);
    CloseHandle(threads[1]);
    CloseHandle(printMutex);
 
    return 0;
}
 
unsigned __stdcall RunThreadA(void *params)
{
    _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
    setlocale(LC_ALL, "french");
    localeSet = TRUE;
 
    WaitForSingleObject(printMutex, INFINITE);
    printf_s("[Thread A] Per-thread locale is enabled.\n");
    printf_s("[Thread A] CRT locale is set to \"%s\"\n",
        setlocale(LC_ALL, NULL));
    printf_s("[Thread A] locale::global is set to \"%s\"\n\n",
        locale().name().c_str());
    ReleaseMutex(printMutex);
 
    return 1;
}
 
unsigned __stdcall RunThreadB(void *params)
{
    while (!localeSet)
        Sleep(100);
 
    WaitForSingleObject(printMutex, INFINITE);
    printf_s("[Thread B] Per-thread locale is NOT enabled.\n");
    printf_s("[Thread B] CRT locale is set to \"%s\"\n",
        setlocale(LC_ALL, NULL));
    printf_s("[Thread B] locale::global is set to \"%s\"\n\n",
        locale().name().c_str());
    ReleaseMutex(printMutex);
 
    return 1;
}

Open in new window

0
 
LVL 40

Expert Comment

by:evilrix
ID: 21761880
>> _beginthreadex()' returns a thread handle, 'disguised' as a 'unsigned long' - just cast it
Interesting info, thanks for that jkr.

>> coincidentially that one applies exactly to your problem
Almost, it doesn't signal the threads to terminate it just spins them up and waits for them to stop. As I understand it this isn't quite what's required; rather, the main thread needs to signal the others to terminate... is that right highqllc? If it is you could deploy the pattern I described above { http:#21759453 } but I should point out this wouldn't have been possible without the info jkr has posted above.
0
 
LVL 40

Expert Comment

by:evilrix
ID: 21762823
Below is a brief example of the pattern I described in my first post.

This should be considered a conceptual example only.  I've made no real attempt at error handling, preferring to preserve brevity for the sake of clarity.

I hope this helps.

-Rx.
#include <iostream>
#include <vector>
#include <cstdlib>
#include <windows.h>
#include <process.h>
 
typedef std::vector<HANDLE> thread_handles_t;
 
HANDLE hEvent = 0;
HANDLE hMutex = 0;
 
void ThreadProc(void * pv)
{
	int nID = reinterpret_cast<int>(pv);
 
	WaitForSingleObject(hMutex, INFINITE);
	std::cerr << "Started thread " << nID << std::endl;
	ReleaseMutex(hMutex);
 
	while(WAIT_TIMEOUT == WaitForSingleObject(hEvent, 0)) { Sleep(0); }
 
	WaitForSingleObject(hMutex, INFINITE);
	std::cerr << "Stopped thread " << nID << std::endl;
	ReleaseMutex(hMutex);
}
 
int main()
{
	hEvent = CreateEvent(NULL, true, false, NULL);
	hMutex = CreateMutex(NULL, false, NULL);
 
	if(hEvent && hMutex)
	{
		thread_handles_t thread_handles;
		for(int nID = 0 ; nID < 20 ; ++nID)
		{
			uintptr_t iptr = _beginthread(ThreadProc, 0, reinterpret_cast<void *>(nID));
 
			if(-1 == iptr)
			{
				std::cerr << "Unable to create thread " << nID << std::endl;
			}
 
			thread_handles.push_back(reinterpret_cast<HANDLE>(iptr));
		}
 
		system("pause");
		SetEvent(hEvent);
		WaitForMultipleObjects(thread_handles.size(), &thread_handles[0], true, INFINITE);
		system("pause");
	}
 
	CloseHandle(hMutex);
	CloseHandle(hEvent);
}

Open in new window

0
 

Author Comment

by:highqllc
ID: 21781514
hey guys,

I have discovered some new complexity in my project that is outside the scope of this question. It has to do more with the communication aspect of the object, and how to pass ack messages back in forth to indicate that shutting down is in progress.

However, the suggestions you have provided seem very appropriate for the simplified question that I asked and will serve as a nice reference.  So, I'm going to close this question and perhaps ask a new on on the problems I'm currently grappling with.

Thanks
0

Featured Post

3 Use Cases for Connected Systems

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, testing some more, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
Often, when implementing a feature, you won't know how certain events should be handled at the point where they occur and you'd rather defer to the user of your function or class. For example, a XML parser will extract a tag from the source code, wh…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question