?
Solved

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

Posted on 2008-06-11
7
Medium Priority
?
3,195 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 2
7 Comments
 
LVL 40

Accepted Solution

by:
evilrix earned 1000 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
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 86

Assisted Solution

by:jkr
jkr earned 1000 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

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

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…
Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

743 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