TThread Resume

TThread Resume

Post by mbaessle » Fri, 30 Nov 2007 20:52:08


Hi all,
I have a problem with my TTread descendants (using BCB 5).
My application uses several threads and I'm subclassing TThread.
The highest level (direct descendant of TThread) instantiates TThread
as suspended and resumes after the constructor has done all its work.

The problem now is that the further down subclass's constructors run
afterwards and therefore concurrent to the Execute().
I have some classes that have long construction code and therefore
really have problems with simultaneous access.

A simplified code looks like this:

class A:public TThread
{
public A();
};

class B: public A
{
public B();
protected Execute();
private int iB;
};

A::A()
:TThread(true)
{
Resume();
}

B::B()
:A(), iB(0)
{
}

B::Execute()
{
iB = 5;
while (!Terminated);
}

iB has different values in the while loop!

I know I can defer the Resume() to the last class in the hierarchy.
But as I have a lot of descendants (and more than one hierarchy level)
I'm searching for a more convenient way.

regards
Matthias
 
 
 

TThread Resume

Post by Mark Jacob » Fri, 30 Nov 2007 23:03:35

If you inherit from TThread, then the constructor takes a boolean argument
which determines whether it is created suspended or not. When you create the
thread with the "new" keyword, simple specify the argument as "true". Works
for me.
--
Mark Jacobs
DK Computing
http://www.yqcomputer.com/

 
 
 

TThread Resume

Post by Clayton Ar » Sat, 01 Dec 2007 02:19:41

If you were using BCB6 or up then this wouldn't be a problem since thread
construction is guaranteed to finish before thread execution begins.
However, since you are using BCB5 you need a different solution.

One solution is to design the class to create itself suspended (as you are
already doing) and make it a requirement that the caller resumes the thread
after construction. This isn't a very bad design anyway since a lot of the
time the caller needs to hook event handlers and initialize other data:

B* b = new B;
b->OnTerminate = &TerminateEventHandler;
b->Priority = tpIdle;
b->Resume();

Clayton
 
 
 

TThread Resume

Post by Team » Sat, 01 Dec 2007 02:55:07


That is because you are calling Resume() in the base class constructor
before the descendant constructors are called. To delay the Resume() until
after all constructors have been called, override the virtual
AfterConstruction() method, ie:

class A : public TThread
{
protected:
//...
virtual void __fastcall AfterConstruction();
public:
__fastcall A();
};

__fastcall A::A()
: TThread(true)
{
}

void __fastcall A::AfterConstruction()
{
TThread::AfterConstruction();
Resume();
}


Gambit
 
 
 

TThread Resume

Post by Team » Sat, 01 Dec 2007 02:58:43


TThread in BCB 6+ uses AfterConstruction() to delay the call to Resume(),
the same way I showed in my other reply. If you want to make your thread
code upgradable to BCB 6+, you could use #if statements, ie:

class A : public TThread
{
protected:
//...
#if (__BORLANDC__ < 0x560)
virtual void __fastcall AfterConstruction();
#endif
public:
__fastcall A();
};


#if (__BORLANDC__ < 0x560)
const bool g_StartThreadSuspended = true;
#else
const bool g_StartThreadSuspended = false;
#endif

__fastcall A::A()
: TThread(g_StartThreadSuspended)
{
}

#if (__BORLANDC__ < 0x560)
void __fastcall A::AfterConstruction()
{
TThread::AfterConstruction();
Resume();
}
#endif


Gambit
 
 
 

TThread Resume

Post by Clayton Ar » Sat, 01 Dec 2007 03:54:35

Again, after all the years that I've been programming with the VCL I can
still learn something new. I had no idea that AfterConstruction() existed
for all TObject descendants.

Clayton
 
 
 

TThread Resume

Post by mbaessle » Sat, 15 Dec 2007 23:03:48

On Thu, 29 Nov 2007 09:55:07 -0800, "Remy Lebeau \(TeamB\)"


...
...

Thanks, that's the comfort solution I was searching for.
Matthias