Reputation: 15
I'm implementing Java style thread in C++. In order to do that I have a Thread::Start function but my problem is that when I use it, it works fine only the first time for some reason once a thread instance call start it finish of but I can't call start again and neither call other thread's start function.
It's my thread constructor:
Thread::Thread()
{
m_handle = (HANDLE)_beginthreadex(0, 0, &call, this, CREATE_SUSPENDED, 0);
}
Thread destructor:
Thread::~Thread()
{
if (m_handle) CloseHandle(m_handle);
}
Call function it's use as a wrapper for Run function:
unsigned int __stdcall Thread::call(void* _this)
{
((Thread*)_this)->Run();
return 0;
}
And it's my Start function:
void Thread::Start()
{
if (m_handle) ResumeThread(m_handle);
}
And the code that have the problem is the following:
The clerk class:
struct Clerk : public Thread
{
Clerk()
{
IsOnService = false;
}
void Run()
{
std::cout << this->GetId() << " receive new customer " << '\n';
Sleep(2000);
std::cout << this->GetId() << " has finished" << '\n';
IsOnService = false;
}
bool IsOnService;
};
Service class:
struct Service
{
Clerk* clerk;
Customer* customer;
Service(Clerk* c, Customer* cu)
{
clerk = c;
customer = cu;
clerk->Start();
}
~Service()
{
delete customer;
}
};
And the main function:
int main()
{
int nClerks = 5;
Clerk* clerks[] = {
new Clerk(), new Clerk(), new Clerk(), new Clerk(), new Clerk()
};
Queue<Customer*> awaitingCustomers;
while (1)
{
if (GetAsyncKeyState(0x43) & 0x7FFF)
{
Customer* newCustomer = new Customer();
awaitingCustomers.Push(newCustomer);
while (!awaitingCustomers.IsEmpty())
{
for (int i = 0; i < nClerks; ++i)
{
if (!clerks[i]->IsOnService)
{
Service* newService = new Service(clerks[i], awaitingCustomers.Pop());
delete newService;
break;
}
}
}
}
}
for (int i = 0; i < nClerks; ++i) delete clerks[i];
return 0;
}
When I run the code above it only call Start function one time instead of call it every time in that I press 'c' key. I need a c++98 solution thx.
Upvotes: 0
Views: 2595
Reputation: 73091
Well, the bad news is that you cannot restart a thread. i.e. Once the thread has exited, it's gone forever and cannot be restarted.
The good news is that there are a couple of things you can do that give you effectively the behavior you want, anyway:
1) Call WaitForSingleObject(m_handle, INFINITE);
and CloseHandle(m_handle);
to clean up the old/exited thread, then launch a new thread the same way you launched the original thread (i.e. by calling _beginthreadex()
and ResumeThread()
and so on). This logic can all be encapsulated inside your Thread
class so that as far as any calling code is concerned, the Thread appears to be "restarted" (albeit with a different thread ID, if that matters).
or, alternatively (if you don't want the overhead of launching a fresh thread every time):
2) Never have your thread exit in the first place. That is, have your thready-entry function do something like this (pseudocode):
unsigned int __stdcall Thread::call(void* _this)
{
while(timeToQuit == false)
{
// Do the normal Thread thing
((Thread*)_this)->Run();
EnterCriticalSection(...);
// we'll block here until the main thread wakes us up
SleepConditionVariableCS(...);
LeaveCriticalSection(...);
}
return 0;
}
Then whenever your main thread wants to "restart" the internal thread, it would call WakeConditionVariable on the Thread object's condition-variable to wake the internal thread out of its post-run sleep, and then the internal thread would call Run()
again. (And if you want the internal thread to quit, you'd do the same thing except set timeToQuit
to true first -- not that timeToQuit
should be a std::atomic<bool>
or similar in order to be thread-safe)
Upvotes: 1