Click to See Complete Forum and Search --> : monitoring completion of threads


stephenprogrammer07
August 27th, 2007, 02:44 AM
Hi ;

I tried asking this question in another section and didn't find the answers useful to solving this problem . So I'll post it hear and hope I get luckier.

I need to launch a thread and monitor when it ends before launching another thread. If the new thread is launched before the old thread has completely released the resources, the app wil crash.

I can't simply use WaitForSingleObject (handle, INFINITE) from the main code because I need continued on-screen animation while the thread runs - and the thread takes a couple of seconds to return.


I just need to know exactly when it returned. This will let me know when I can optionally launch a new thread.

"I'm sure there has to be a simple solution. seems like a very common need "

My app is a game. So I have a built in game loop which can use to keep checking if the thread has returned . Here's my attempt at solving this issue .

1. Here's a stripped down sample of the main code game loop



int main()
{
ThreadManager tmanger;

while(true)
{

if(tmanager.hasThreadReturned() )
{

tmanager.launchThread(&tmanager) ;
}


}
};



my hope is that ThreadManager will run as a thread which will be responsible for launching the appropriate thread and it will report back the results on weather the thread is finished or not.

Only after the thread is finished it will launch a new one.
Here's what my stripped down ThreadManager code looks like





ThreadManager::ThreadManager()
{
m_dwThreadID = 0 ;
m_hThread = 0 ;
threadStatus = true;
};

ThreadManager::~ThreadManager()
{
CloseHandle(m_hThread);
};

bool ThreadManager::hasThreadReturned()
{
return threadStatus;
};

void ThreadManager::setThreadFinishedStatus(bool s )
{
if(s)
{
printf("\nThreadManager::setThreadFinishedStatus set to
true\n");
}else
printf("\nThreadManager::setThreadFinishedStatus set to
false\n");

threadStatus = s;
};



bool ThreadManager::launchThread(ThreadManager *whatever)
{

m_hThread = CreateThread(0,
0,
ThreadFunc,
(void *)whatever,
0,
&m_dwThreadID);



if(!m_hThread)
{
return false;
}

return true;
};


HANDLE ThreadManager::TheHandle(void) const { return m_hThread;
};

DWORD WINAPI ThreadManager::ThreadFunc(LPVOID pvParam)
{

Speech sp ;
ThreadManager* t = (ThreadManager*) pvParam;

t->setThreadFinishedStatus(false );

sp.Create("this is a sample param passed in") ;

::WaitForSingleObject(sp.TheHandle(), INFINITE );

t->setThreadFinishedStatus(true );


};





Speech sp is another Thread that takes bit of time to run.

So I tried using WaitForSingleObject(). The main code loop does pick up that the bool value is false and so it waits until it is true again.

However my application still crashes.
1 possible reason that it crashes might be because the Speech thread has not released it's resources.

I'm guessing that might be the case because ::WaitforSingleObject(sp.Handle(), INFINITE) is holding onto the handle thus keeping the thread object alive . and not calling it's destructor


Any thoughts on this ?

Thanks in advance - I definitly appreciate any info

Stephen

exterminator
August 27th, 2007, 04:15 AM
Here are the threads you would use:

Main thread - execution of main and starts all other threads

SpeechThread - started by main thread. It in turn starts multiple other threads that you are talking about and it is the one that uses WaitForSingleObject for those threads to complete. This way the main thread or any other thread started by main thread keep going on without a block since they won't be the one calling WaitForSingleObject. Now, on top of this, what I have been suggesting is that you don't need to start multiple threads from SpeechThread - just one would do which keeps executing what you achieve via the sequential thread runs. This is what I was stressing in that last thread you started.

This is what I have been trying to convey, I cannot get more explicit than this. If this doesn't work, since I am a beginner with threads, my understanding would be limited enough to help you out.

upashu2
August 27th, 2007, 04:51 AM
However my application still crashes.
1 possible reason that it crashes might be because the Speech thread has not released it's resources.
Some modification may help to find out problem

1. Instead of setting a variable true or false, you should use a variable to count the no of threads and when it is zero, assume no thread is running and for this you should use InterlockedIncrement() and InterlockedDecrement() functions.
2.It may happen : If thread just change the variable and not finished yet completely and at same time you checked the value of variable and started another one. for this case just try to provide delay of 10ms before starting thread, just for testing.
3.If any resource sharing is used, you should use critical section or mutex or semaphore.Consider it.

JVene
August 27th, 2007, 03:22 PM
In my own work I have a library of objects representing threads and related components (critical sections, locks, mutexes, etc.)

One such object is a QueProcessor. Instantiating it represents a thread (one is launched as the result of it's instantiation). It's first task is to wait for instructions.

The QueProcessor object accepts any derivative of a "ProcBase" object (a pure virtual in my own case), which loosely represents a delegate or pointer to a function (likely a member function). Submitting 'procs' to the QueProcessor gives it work to do, and the QueProcessor stores subsequent procs for operation in sequence.

As such, in your design requirement, I could simply stuff two procs into the QueProcessor, the second being the dependent upon the first (and even streams of such pairings). They are executed in order (using a FIFO queue).

Now, there is no means to guarantee that another QueProcessor won't attempt an unsynchronized call, and perhaps its wise to see to it that can't be done. Many would allow that particular and unlikely happenstance to be left to the programmer's own discipline, but to enforce that only one such thread could be active, the QueProcessor responsible could be made the member of an executive in charge of the operations, which itself is made a singleton object. Thus, per application, only one thread (one queue) and therefore only one stream of contiguous operations would be possible.

I find many think of threaded programming in terms of launching a thread for a particular purpose, rather than making a thread more general purpose and serving tasks by a process descriptor (some template representing pointers to member functions and the like). Experience shows me the latter is far more productive and generally faster, since the time to service the next task doesn't involve launching a thread while a previous task spends its last moments shutting one down.

stephenprogrammer07
August 27th, 2007, 05:56 PM
@exterminator
Okay I see where you said this in the previous thread. Maybe I missed it because I was staying up very late at night to do this. That suggestion on a SpeechThread is what I have demonstrated in my code above.



About mutex locks , critical sections and semaphores.
I'm familiar with java threads - but not c++ thread behavior. So I'm going to have do some research on mutex , critical sections and semaphores. If anyone knows of a good tutorial online for those I'll be glad to read it.



Also in the mean time I'm going to try that QueProcessor solution. I'll just make 1 Thread which will speak and wait speak and wait.
Rather than trying to launch a separate thread for each event. This could eliminate that problem with the shared resource as well which crashes with each new thread.

stephenprogrammer07
August 28th, 2007, 04:07 AM
Okay I think I fixed this problem.
I didn't use any mutex or semaphores or special int out process.

I just used the thread launching a thread and then put some flag setters at the beginning and end of the DWORD WINAPI threadfunc

When threadfunc is about the end, the last line is just as flag setter - and I use that to keep track of when the thread is finished.

Then in the main code it turns out to be critical that I give the 20 milliseconds of sleep time before I act upon the flag changes - probably because there is a little lag time between createthread and DWORD WINAPI threadfunc .


interesting stuff.
I need to sit down and learn multithreaded programming in case i get into a tighter spot.

Arjay
August 28th, 2007, 02:29 PM
When threadfunc is about the end, the last line is just as flag setter - and I use that to keep track of when the thread is finished.I'm not sure a flag setter is needed. In your previous design, I assumed you couldn't use WaitForSingleObjects before because you were launching in the UI thread, but now that you are launching from a secondary thread, you should be able to use this function (or the other WaitForxxx functions). Using a hardcoded value to wait for resources to be released may be problematic. For one thing, you have a potential for starting a second thread before any worker thread stack objects have gone of of scope. (I'm talking about the interval between setting the flag and the thread proc completely finishing). Instead, you may consider to protect the resources with a cs or mutex inside the worker thread and attempt to acquire the lock there. That way, your secondary can simply wait for the worker thread to finish with WaitForSingleObject and immediately launch another worker thread. With this new worker thread starts it attempts to acquire the lock and when acquires it can continue. This division of responsibility allows the worker thread to handle its own resource locking/unlocking and allows the launching thread to simply launch and wait without worrying about resources.

stephenprogrammer07
August 28th, 2007, 03:18 PM
sounds good.
Could you give a little code sample of that.
I'll give you the code template.
Perhaps you could fill in how to mutex works.



#include <windows.h>

#ifndef ThreadManager2_h
#define ThreadManager2_h
class ThreadSubject
{
private:
DWORD m_dwThreadID;
HANDLE m_hThread;
bool threadStatus;

public:

ThreadSubject();
~ThreadSubject();
bool hasThreadReturned();
void setThreadFinishedStatus(bool s );
bool launchThread(ThreadSubject *w);
HANDLE TheHandle(void) const;
static DWORD WINAPI ThreadFunc(LPVOID pvParam);
};
#endif

#include <windows.h>
#ifndef ThreadManager_h
#define ThreadManager_h
class ThreadManager
{
private:
DWORD m_dwThreadID;
HANDLE m_hThread;
bool threadStatus;

public:

ThreadManager();
~ThreadManager();
bool hasThreadReturned();
void setThreadFinishedStatus(bool s );
bool launchThread(ThreadManager *w);
HANDLE TheHandle(void) const;
static DWORD WINAPI ThreadFunc(LPVOID pvParam);

};
#endif



#include <windows.h>
#include <stdlib.h>
#include <iostream>
#include <ThreadManager.h>
#include <ThreadSubject.h>

ThreadManager::ThreadManager()
{
m_dwThreadID = 0 ;
m_hThread = 0 ;
threadStatus = true;
};

ThreadManager::~ThreadManager()
{
CloseHandle(m_hThread);
printf("\n ThreadManager::~ThreadManager() destructor was called before going out of scope" ) ;
};

bool ThreadManager::hasThreadReturned()
{
return threadStatus;
};

void ThreadManager::setThreadFinishedStatus(bool s )
{
threadStatus = s;
};



bool ThreadManager::launchThread(ThreadManager *whatever)
{

m_hThread = CreateThread(0,
0,
ThreadFunc,
(void *)whatever,
0,
&m_dwThreadID);

if(!m_hThread)
{
return false;
}

return true;
};


HANDLE ThreadManager::TheHandle(void) const
{
return m_hThread;
};

DWORD WINAPI ThreadManager::ThreadFunc(LPVOID pvParam)
{
ThreadSubject ts;
ts.launchThread(&ts);
::WaitForSingleObject(ts.TheHandle(), INFINITE);
Sleep(3000);
printf("\n getting ready to exit ThreadFunc");


};













#include <windows.h>
#include <stdlib.h>
#include <iostream>
#include <ThreadSubject.h>

ThreadSubject::ThreadSubject()
{
m_dwThreadID = 0 ;
m_hThread = 0 ;
threadStatus = true;
};

ThreadSubject::~ThreadSubject()
{
CloseHandle(m_hThread);
printf("\n ThreadSubject::~ThreadSubject() destructor was called before going out of scope" ) ;
};

bool ThreadSubject::hasThreadReturned()
{
return threadStatus;
};

void ThreadSubject::setThreadFinishedStatus(bool s )
{
threadStatus = s;
};



bool ThreadSubject::launchThread(ThreadSubject *whatever)
{

m_hThread = CreateThread(0,
0,
ThreadFunc,
(void *)whatever,
0,
&m_dwThreadID);

if(!m_hThread)
{
return false;
}

return true;
};


HANDLE ThreadSubject::TheHandle(void) const
{
return m_hThread;
};

DWORD WINAPI ThreadSubject::ThreadFunc(LPVOID pvParam)
{

Sleep(3000);
printf("\n getting ready to exit ThreadSubject ThreadFunc");


};





#include <cstdlib>
#include <iostream>
#include <ThreadManager.h>

using namespace std;

int main(int argc, char *argv[])
{ int x = 0;
ThreadManager tm;
while(x<15)
{ x++;
printf("\nlaunching new Thread tm.launchThread(&tm);");
tm.launchThread(&tm);
Sleep(4000);
}
system("PAUSE");
return EXIT_SUCCESS;
}





Thanks in advance for showing me the correct way to use mutex

Stephen