Solved

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

Posted on 2008-06-11
7
3,157 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
Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
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

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
C++ Language error 28 241
Dynamically allocate memory 9 62
Eclipse IDE - Cannot copy/paste from console output 8 250
max float value 3 51
Written by John Humphreys C++ Threading and the POSIX Library This article will cover the basic information that you need to know in order to make use of the POSIX threading library available for C and C++ on UNIX and most Linux systems.   [s…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

791 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