[C++] Best way to create and end threads

Started by
6 comments, last by adriano_usp 16 years, 11 months ago
Hi, I tring to find a good way to externally end a thread. Please, consider the following code (very simple):

class CL_THREAD
{
public:
  CL_THREAD();
  ~CL_THREAD();	            
	
private:

  HANDLE thHandle;

  static void threadFunc(void *arg)
  {
    ...

     _endthread();			
  }

};

CL_THREAD::CL_THREAD()
{
  thHandle = (HANDLE) _beginthread( threadFunc, 0, NULL );
			
  if(!thHandle) 
    MessageBox(0,"_beginthread failed.",0,0);
}

CL_THREAD::~CL_THREAD()
{
  ::TerminateThread(thHandle,0);			
}

The TerminateThread() function could be dangerous in some cases. So, I'm searching a better way to end threads. Please, could anybody help me? Thanks in advance.
Advertisement
The best way to terminate a thread is by returning from the thread function you pass into _beginthread. Your call to _endthread at the end of your thread function is redundant, because it will be called when the thread returns from that function anyways.
volatile bool running = true;void threadFunc(){  while (running) {    // do the thread stuff  }}....// when done with threadrunning = false;


This is one way to do it.
First I just set the "bool can_run" flag to false, in hopes that the thread terminates on its own,
done in my "stop" function.
This is followed by my calling thread running "join" to wait for the thread to finish.

I also have a "forcejoin" that waits a specified time for the thread to terminate then calls terminatethread.

And in my destructor, I set can_run to false. and forcejoin with a default timer.
Thanks friends. I rewrote the code to make the thread returns:

class CL_THREAD{public:  CL_THREAD();  ~CL_THREAD();	            	private:  bool terminate;  HANDLE thHandle;  static void threadFunc(void *arg)  {     CL_THREAD *p = (CL_THREAD*)arg;     p->Func();			  }  void Func()  {    while(terminate == false)    {      ...           }  }};CL_THREAD::CL_THREAD(){  terminate = false;  thHandle = (HANDLE) _beginthread( threadFunc, 0, NULL );			  if(!thHandle)     MessageBox(0,"_beginthread failed.",0,0);}CL_THREAD::~CL_THREAD(){  terminate = true;			}


So, the thread is terminated by calling the destructor. But... is there no way to instantly terminate the thread without using TerminateThread()? That is, without waiting the while loop be completed.

Thanks in advance
Quote:Original post by adriano_usp
Thanks friends. I rewrote the code to make the thread returns:

*** Source Snippet Removed ***

So, the thread is terminated by calling the destructor. But... is there no way to instantly terminate the thread without using TerminateThread()? That is, without waiting the while loop be completed.

Thanks in advance


Ouch on several levels.

First, you never call destructor, unless you're doing your own custom new overloaded memory allocation.

Second, calling delete X will destroy the object and its resources, but the thread will keep on running. By the time it gets to check the flag, the location of that flag may be who knows where.

Forcing thread termination is not possible in many libraries, or is strongly discouraged in others. There's plenty of reasons for that, but terminating a thread while it's running is generally considered as: Do Not Do It (tm).

Here's one way, if you insist on wrapping the classes:
class Thread {  Thread()     : running( true )    , completed( false )  {    // start thread by passing run() as its function  }  // override this to implement what the thread should do  virtual void threadFunc() = 0;  void stopThread( int timeout_ms )   {    // poll for completion every 25 ms to avoid hogging down the CPU    int granularity = 25;    timeout_ms /= granularity;    int i = 0;    // Signal thread to stop running    running = false;        // Wait for thread to complete    while (!completed && (i < timeout_ms ) ) {      Sleep(granularity);      i += granularity;    }    // If thread didn't complete, we have a problem    if (!completed) throw std::exception("Failed to stop the thread");  }private:  void run()   {    while ( running ) {      threadFunc();    }    // Once requested to exit, signal that we're done    completed = true;  }  volatile bool running;  volatile bool completed;}


Note that this isn't a working example.

The virtual function is there only as a place holder, you can't really do that.

The whole demonstration serves merely to show how to wait for a thread to finish. You cannot force a thread to stop, and you really do not know if the thread will stop when requested.

This is what concurrent/asynchronous programming brings along. And it's a Bad Idea(tm) to fight against these mechanisms. There are far too many problems that they bring about.
Quote:Original post by Antheus
The whole demonstration serves merely to show how to wait for a thread to finish.


IMO the right way to wait for a thread to terminate is to use the WaitForSingleObject API.

A very simple example:

struct ThreadBase{    static DWORD WINAPI ThreadEntry(void* pThreadClass)    {        return ((ThreadBase*)pThreadClass)->Main(); // You can use a better, safer cast.    }    virtual DWORD Main() = 0;    void Create()    {        CreateThread(NULL, 0, ThreadEntry, this, CREATE_SUSPENDED, &threadID);    }    // ----------------------------    void Start()    {        ResumeThread(threadID);            }    // ----------------------------    // /!\ CALLING THIS FROM THE THREAD YOU'RE TRYING TO END WILL DEADLOCK :)    void Stop()    {        keepRunning = false; // May want to use a InterlockXXX method, and/or to declare keepRunning volatile                // optionnaly wait for the thread to terminate, you can even set a timeout        WaitForSingleObject(m.threadID, 0xFFFFFFFF);    }    DWORD threadID;    bool keepRunning; // Subclasses are responsible for checking this value.}struct SomeModule : public ThreadBase{    virtual DWORD Main()    {        while(keepRunning)        {            /* Do whatever */        }        return 0; // or whatever error code or anything you wish.    }}int main(){    SomeModule m;    m.Create();    m.Start();    bool appRunning = true;    while(appRunning)    {        /* Do whatever */    }    m.Stop();       }   


And it's better (recomanded by microsoft) to use the _beginthread/etc. methods just as you did.

[Edited by - janta on May 4, 2007 2:32:28 PM]
Thanks for the explanations, friends.

This topic is closed to new replies.

Advertisement