OWL NExt - Knowledge Base

[ Home | Contents | Search | Next | Previous | Up ]

TThread Run () in OWL

Date: 12/1/99
Time: 9:57:35 PM

Question:

How to use Run () in a TThread in OWL?

Answer:

There is a missing function in the docs:

virtual int Run();

Basically, it goes like this:

a) You derive from TThread and override Run().  Any code executing from this
Run() is in the new thread owned by the TThread class.

b) When you call Start() will your new thread object, TThread creates a new
windows thread and makes it call your Run() function

c) You have to be aware of the valid states and state transitions.  For
example, when you create a new TThread object, it is in the TThread::Created
state.  The only valid transition is to TThread::Running (this is done by
calling Start()).  So in other words, you can't create a TThread object and
not call its Start(). If you try to delete this object before calling
Start(), it will throw an exception.  Also, the new thread is done when you
return from Run() or when you call Exit() (i think).   Basically, you must
call Start() exactly once for each instance of TThread.   This means that you
must call Start() before deleting the object and you can only can Start()
once during the lifetime of the object.  All this kind of stuff is in the
docs, but I thought I would mention it anyway.

If you want a slick way of controlling a thread without being required to
derive from it, check out the code below.

Basically, any class that needs multithreading, just derive from Runnable
and override int Run().  When you're ready, you can create a new ThreadEx
object like:


// assuming 'this' is an instance of an object derived
// from Runnable
//
ThreadEx* mythread = new ThreadEx(this);
myThread->Start();

you now have an object that can USE threads without being a thread object
itself and without having to create a separate DoSomethingInAnotherThread
class derived from TThread every time you need another functionality in
separate thread.  The object using a ThreadEx can create a new thread, run
it, delete it, create another, run it, delete it ....

Here is the code:


//
// declaration
//
class ThreadEx;

class Runnable {
  public:
    Runnable();

  protected:
    virtual int Run() = 0;

    friend ThreadEx;
};

class ThreadEx : public TThread {
  public:
    ThreadEx(Runnable* runnable);
    virtual ~ThreadEx();

    int Run();
    bool ShouldTerminate();
    TThread::THandle Start();
    TThread::THandle GetHandle();
    void Kill();


  protected:
    Runnable* runnable;
    TThread::THandle threadHandle;
};



//
//
// Runnable implementation
//
Runnable::Runnable() {
}

//
//
// ThreadEx implementation
//
ThreadEx::ThreadEx(Runnable* runnable) {
  if(runnable == NULL)
    xmsg("ThreadEx: Invalid Runnable").raise();

  this->runnable = runnable;
}

ThreadEx::~ThreadEx() {
  switch(GetStatus()) {
    case Created:  Start();
    case Suspended:  Resume();
    case Running:  TerminateAndWait(5000);
          if(GetStatus() != Finished)
                       Kill();
                     break;
  }
}

TThread::THandle ThreadEx::Start() {
  threadHandle = TThread::Start();
  return threadHandle;
}

TThread::THandle ThreadEx::GetHandle() {
  return threadHandle;
}

//
// Avoid using Kill().  It will obliterate the thread and any resources that
were allocated by
// your code will not be freed.
//
void ThreadEx::Kill(){
  ::TerminateThread(threadHandle, 0);
}

bool ThreadEx::ShouldTerminate(){
  return TThread::ShouldTerminate();
}

int ThreadEx::Run() {
  return runnable->Run();
}

Last changed: July 14, 2001