Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 3260
  • Last Modified:

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

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
highqllc
Asked:
highqllc
  • 4
  • 2
2 Solutions
 
evilrixSenior Software Engineer (Avast)Commented:
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
 
highqllcAuthor Commented:
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
 
evilrixSenior Software Engineer (Avast)Commented:
>> 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
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
jkrCommented:
'_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
 
evilrixSenior Software Engineer (Avast)Commented:
>> _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
 
evilrixSenior Software Engineer (Avast)Commented:
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
 
highqllcAuthor Commented:
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

Receive 1:1 tech help

Solve your biggest tech problems alongside global tech experts with 1:1 help.

  • 4
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now