TThread - why are updated property values not reflected from the perspective of a /different/ thread?

TThread - why are updated property values not reflected from the perspective of a /different/ thread?

Post by Riaan Mol » Tue, 21 Sep 2010 18:22:59


Hi guys,

Been wondering about this for a while now, and I was hoping somebody
could shed some light.

Let's assume you have a worker thread that performs some lengthy op,
and there is a another thread (say, the main VCL thread) that monitors
a flag which is a property of the worker thread class. Updating the
property value from the worker thread does not reflect when you call
the property getter from another thread (even if all access to the
data member is protected by a critical section), and I'd like to know
why. Please take a look at the following example:

//////////////////////////////////////////////////////////
type
TWorkThread = class(TThread)
private
fCritSect : TCriticalSection;
fCompleted : boolean;
procedure SetCompleted(value : boolean);
function GetCompleted : boolean;
protected
procedure Execute; override;
public
constructor Create; reintroduce;
destructor Destroy; override;
property Complete : boolean read GetCompleted write SetCompleted;
end;

//////////////////////////////////////////////////////////
constructor TWorkThread.Create;
begin
inherited Create(true);

FreeOnTerminate := false;
fCritSect := TCriticalSection.Create;

resume;
end;

//////////////////////////////////////////////////////////
procedure TWorkerThread.SetCompleted(value : boolean);
begin
fCritSect.Enter;
try
fCompleted := value;
finally
fCritSect.Leave;
end;
end;

//////////////////////////////////////////////////////////
function TWorkerThread.GetCompleted : boolean;
begin
fCritSect.Enter;
try
result := fCompleted;
finally
fCritSect.Leave;
end;
end;

//////////////////////////////////////////////////////////
procedure TWorkerThread.Execute;
begin
try
{ Perform some lengthy operation }
finally
Completed := true; // Critical section is used by using the setter
(and it definitely updates fCompleted).
end;
end;

The thread that invokes the worker thread (let's assume it's the main
VCL thread that needs to remain responsive) does something like this:

//////////////////////////////////////////////////////////
procedure DoSomething;
begin
{ create work thread }
with TWorkThread.Create do
try
{ and wait for it to finish with a cheap and *** loop }
repeat
Application.ProcessMessages;
Sleep(150);
until Complete;

{ The loop never finishes - Complete NEVER becomes true, even
though the worker thread
is definitely completing and using the setter (I've verified
this), and so it's an infinite loop. WHY? }

finally
free;
end;
end;

Please do not preach to me about this code :-) , I know that the
correct way to do this sort of thing is by using message posting or
sync objects. I would just like to know why the behaviour of the
application is not as one would expect.

Any explanations would be greatly appreciated!

Thanks and regards,
Riaan
 
 
 

TThread - why are updated property values not reflected from the perspective of a /different/ thread?

Post by Maarten Wi » Tue, 21 Sep 2010 21:15:42


[...]

<snip code>


But you _are_ using synchronisation objects. That code looked exactly
right to me, except for the absence of the overridden destructor.

I can offer no explanation. Different threads have their own program
counter, but they share all data that isn't in threadvars. Instance
fields shouldn't be a problem and you're even protecting the read
accessor. I am at a loss. It's probably something completely unrelated.

Was that code pasted, or re-typed?

Groetjes,
Maarten Wiltink

 
 
 

TThread - why are updated property values not reflected from the perspective of a /different/ thread?

Post by alanglloy » Tue, 21 Sep 2010 23:55:04

I'm by no means an expert on threads (I'll leave that to Maarten) but
you seem to have TWorkThread.fCompleted which is get or set by
TWorkERThread methods.

Is Maartens query on copying valid, or is there similar named
variables in both threads, or have you been caught by the dreaded
"with" not with-ing.

Alan Lloyd
 
 
 

TThread - why are updated property values not reflected from the perspective of a /different/ thread?

Post by Maarten Wi » Wed, 22 Sep 2010 05:43:10


I'm not, either.

Groetjes,
Maarten Wiltink
 
 
 

TThread - why are updated property values not reflected from the perspective of a /different/ thread?

Post by Jami » Wed, 22 Sep 2010 09:31:13

iaan Moll wrote:
Well, I copied the code and corrected the declarations you made, you
have a TworkThread and a TworkerThread..
I had to make one of the other on my end to get it to even compile. If
it compiles on your end, this only means you have another thread you're
getting mixed up in...

In any case, it works fine on my end when I use the members in the
same thread class..

Have a good day and may your errors be many..