Problem with TThread Suspend

Problem with TThread Suspend

Post by Wayne Fuqu » Thu, 31 Aug 2006 04:48:58


i,

I am having a problem with TThread Resume / Suspend().

I have searched newsgroups.borland.com and I can see...
There is a timing issue with Suspend/Resume() since they do not synchronize
with each other internally. And I read... Waking from Threadmare.

It seems to me like Suspend() sets Suspended, but otherwise
acts like a no_op.

The code below is a very reduced version of my original code to
show what I would like to do.
Many elements of my original code have been removed or replaced.

The included code can be setup to run in two modes...
one mode (the default mode)
demonstrates how the code operates without the problem block of code.
the other mode includes the problem block of code and
demonstrates how the code fails.

Without the problem block, the Thread code in Unit2
moves some Shapes left and right, no problem.

However, I would like to provide for a user to input some
values to predict where the block will move From
and where it is to move To.

When the problem block of code is included,
the From_edit field is made visible so the user can provide a value.
Then the code enters a while loop to wait for the user,
if the value is OK, the code continues,
otherwise the loop will Suspend() the Thread to wait for user input.

A second loop is then provided for the To_edit field value.

This problem block of code is located in the following subroutine of Unit2

void __fastcall MyTest::DoMove() //Move a Shape from one area
to another
{
//Debug... The following block of code has problems,
// Debug can be used to remove the block and thus demonstrate
// how the rest of the code operates without this block of code.
// The default is set to skip the following block of code
// delete the following line (or comment it) to test the block.
#define Debug
#ifndef Debug
...



----------------------------------------------------------------------------
-------
The following is the reduced version of my original code.





=====================================================
Code for Unit1.h
//--------------------------------------------------------------------------
-

#ifndef Unit1H
#define Unit1H
//--------------------------------------------------------------------------
-
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
//--------------------------------------------------------------------------
-
class TForm1 : public TForm
{
__published: // IDE-managed Components
TButton *ButtonStart;
TPanel *Panel1;
TShape *Shape1;
TShape *Shape2;
TShape *Shape3;
TLabel *Label1;
TLabel *Label2;
TLabel *Label3;
TLabeledEdit *LabeledEditFrom;
TLabeledEdit *LabeledEditTo;
TButton *ButtonTerm;
void __fastcall ButtonStartClick(TObject *Sender);
void __fastcall LabeledEditFromChange(TObject *Sender);
void __fastcall LabeledEditToChange(TObject *Sender);
void __fastcall FormCreate(TObject *Sender);
void __fastcall ButtonTermClick(TObject *Sender);
private: // User declarations
bool ThreadsRunning;

int num;
int fromPeg;
int toPeg;

void __fastcall TForm1::ThreadDone(TObject *Sender);


public: // User declarations
TShape *Shape[3];
int pegCenter[3];
 
 
 

Problem with TThread Suspend

Post by Team » Thu, 31 Aug 2006 10:45:25


Not true. It does call the Win32 API SuspendThread() function as well.




DO NOT use the OnCreate event in C++! It is a Delphi idiom that produces
illegal behavior in C++, as it can be triggered before the constructor. Use
the actual constructor instead.


You are setting the ThreadRunning before the thread is actually created.
You should set the value afterwards instead, in case the thread fails to be
created and/or begin running.

Besides that, why even use the ThreadsRunning variable at all? You are only
running 1 thread at a time to begin with, so your variable is pretty much
useless..


Why are you calling ThreadDone() directly, instead of letting the thread
trigger it normally? What you should be doing instead is calling the
thread's WaitFor() method after calling Terminate(). That will make the
main thread block until the thread is fully terminated (Terminate() does not
wait for that), while still allowing event handlers to be triggered. This
also allows you the oppurtunity to better free your thread when it is
finished running and the MainForm is done using it.


Do not use that property in the code you showed. Your MainForm code is
dependant on the thread sticking around until you explicitally terminate it.
If the thread terminates prematurely, it is going to free itself too early,
and your MainThread code will crash with Access Violations.


That can be very dangerous to call in a synchronized method. The thread
will not be able to exit from Synchronize() while the thread is suspended,
which will potentially block any other thread that calls Synchronize()
afterwards.


Gambit

 
 
 

Problem with TThread Suspend

Post by Wayne Fuqu » Sat, 02 Sep 2006 07:58:47

Remy Lebeau (TeamB) < XXXX@XXXXX.COM > wrote in message
news:44f4edf6$ XXXX@XXXXX.COM ...

Oop!, I was being a bit facetious here.

On a more serious note...
This comment was in responce to my efforts to debug this code.
While using Breakpoints and Step mode, when I steped at the Suspend()
statement the program advanced to the next statement (which is the top of
the loop) with no discernable action taken to indicate that the unit had
been placed into Suspend mode.

If I look, I can observe that the value of Suspended was changed from false
to true.

The Thread Status View Showed
Unit2 (my: MyTest Thread) State-Stopped Statue-Stepped
both before and after Stepping. Then it just continues to loop; forever.

Which explains why I had to put the If statement around the Suspend()
statement.
I didn't need an infinite number of calls to Suspend().

I had expected the first call to Suspend() to cause the Thread to be
Suspended and the while loop to wait for a Resume().

Use

OK - seems a little surprising but I moved the code to the constructor.

be
only

I had based my Thread on the Borland Example found in the following
directory...
C:\Program Files\Borland\CBuilder6\Examples\Apps\Threads
which used three Threads.

I keep the ThreadsRunning idea from the Example even though I only have one
Thread, thinking that I may add another Thread. If not, I can remove this
bit of code later.

However, your comment made me wonder about this dumb mistake; setting
ThreadsRunning before creating the Thread. I knew that I had copied the
ThreadDone routine directly from the Example. But now I'm thinking that
maybe I hadn't paid much attention to how the Example had set the initial
value for ThreadsRunning; so I loaded the Example and reviewed how this
variable was initialezed. Would you beleave...
ThreadsRunning = 3;
and, before creating any of the three Threads.

It also used the OnCreate event.

not

Brain fade! I forgot that Terminate() would trigger ThreadDone().
The call to ThreadDone() has been removed.

it.
early,

Again the Example used the FreeOnTerminate property this way, so I did.
I need to think about this comment for a while to fully understant it.


Upon first reading this comment, I though the dangerous element was related,
somehow, to the use of both these statements together. And up to this point
all the comments were good and usefull, but nothing fixed my Thread problem.

But while writing this response, I keep thinking about this last comment.
After rereading it, I saw the more importent relationship of calling
Suspend() while in a Synchronize() routine. I was not familiar with the
Synchronize() concept or now it worked (somewhat like a lock/unlock). I had
not realized that it required an "exit" to complete the unlocking. Finally,
I began to realize that this could be more then "dangerous", it might be
fatal.

So I tryed a little experiment...
I moved the Suspend() out of the Synchronize(DoMove) routine, and into the
Move() routine. Then I found a glimmer of hope when the Thread Suspended
and I was able to enter a value for "From" befor the job hungup again.

That was good but I couldn't see how I could get my routine to Suspend() at
the right place if it had to "exit" my Synchronize(DoMove) routine befor it
sould call Suspend().

It took a while, but it finally became clear, what I needed was a state
m
 
 
 

Problem with TThread Suspend

Post by Team » Sun, 03 Sep 2006 20:10:37


Suspend() does not suspend the calling unit. It suspends the thread object
that Suspend() is called upon.


Then the thread object that you called Suspend() on was actually suspended.


As it should be. You are not suspending the loop itself. You are
suspending the thread that the loop accesses. Those are very different
issues. Unless the loop is inside the thread itself, then suspending the
thread has no effect on the loop that is running in a different thread.


It does.


Only if the while() loop is inside the thread itself. Otherwise, no.


Of course it is. Borland has put a LOT of effort into bringing C++
up-to-date as part of the BDS product line, after Borland "discontinued" BCB
a couple of years ago.


Yes, there is a point to it. Borland does go through bug reports regularly.
Use QualityCentral ( http://www.yqcomputer.com/ ) to submit reports. QC is even
integrated inside of BDS.


Gambit
 
 
 

Problem with TThread Suspend

Post by Bruce Larr » Mon, 04 Sep 2006 20:33:07


Hi all...

I'd like to chime in here briefly... I've gone form zero threads in my main app
to 5 or 6 in the last year or two.. all implemented via TThread... I had some major
reworking to do on one of them moving from BCB6 to BDS2006... but there is no doubt
that the results are worth it as the advantages in functionality are myriad...

I read most of these threads regarding threads (ouch! that's worse that finger nails
across a chalkboard! sorry...) They too tricky to treat as trivial and too useful
to ignore...

One more thing, Mr. Lebeau, your font of knowledge and your service to your peers
surely is as greatly appreciated as it is impressive and I'd suspect (albeit from here
in the wilderness...) inadequately rewarded, at least in the coin of the realm stuff?

Unless of course we're communicating cross-dimensionally? (like I said the view, 'from
the wilderness..')

Thanks,

Bruce Larrabee
 
 
 

Problem with TThread Suspend

Post by Pete Frase » Tue, 05 Sep 2006 00:21:55

I believe that as a TeamB member Remy gets nice gifts of BDS2006 every year
as well as free trips to meet Borland folk so he does get something back,
but not nearly as much as he's worth.
Pete
 
 
 

Problem with TThread Suspend

Post by Team » Wed, 06 Sep 2006 04:45:57


You are correct that there are such perks to being a TeamB member.


I always welcome donations :-) Hardware, software, money, it's all good ;-)


Gambit
 
 
 

Problem with TThread Suspend

Post by JD » Wed, 06 Sep 2006 13:05:40


Even adoration or especially so?

~ JD