Talking to a thread

I've used threads in the past to do an intensive process, like a sort or a file search.  In each case, they've terminated with a result.  That's fine.
But how do I talk to a thread to change its state, or to change its execution path, or to trigger it to do things?
I am thinking of an object that would normally be descended from TObject, but is now descended from TThread.  Some form of state machine, but one that does some heavy but short term processing or network access when the state changes.
I also need it to have some form of event-based reporting to the main thread.  Is there any way to make this work without it having to wait for the main thread?  In either case, how do you do it?
LVL 1
bcrotazAsked:
Who is Participating?
 
JimBob091197Connect With a Mentor Commented:
K, then, I assume I can answer this question too...

Cheers,
JB
0
 
JimBob091197Commented:
Hi

I'm not sure if I fully understand what you need, but here goes.

To get a thread to change its actions, you must put checks in its execute method.
E.g.
procedure TMyThread.Execute;
begin
  while (not Terminated) do
    if (MustDoThis) then
      DoThis
    else    
      DoThat;
end;

Your main form can then control the value of MustDoThis as the thread is running.

You can get the thread to trigger an event in the main form by getting the thread to call a procedure in the main form.
E.g.
TMyThread = class(TThread)
  procedure Execute; override;
end;

TMyForm = class(TForm)
public
  MyThread: TMyThread;
  procedure MyThreadIsDone(Sender: TObject);
end;

The form would create the thread when needed:
procedure TMyForm.Button1Click(Sender: TObject);
begin
  MyThread := TMyThread.Create(False);
end;

The form would also implement "MyThreadIsDone":
procedure TMyForm.MyThreadIsDone(Sender: TObject);
begin
  MyThread := nil;
  ShowMessage('My Thread is finished.');
end;

The thread would call the form's procedures when needed:
procedure TMyThread.Execute;
begin
  while (not Terminated) do
  Etc.....
  MyForm.MyThreadIsDone(Self);
end;

Does this help, or am I barking up the wrong tree?
JB
0
 
bcrotazAuthor Commented:
OK....
Can you use an event property in the thread?
Just to make the external procedure calling easier...
If so would you use:

private
  FMyEvent: TNotifyEvent;

...

procedure FireMyEvent;
begin
  if Assigned(FMyEvent) then
    FMyEvent(Self);
end;

...
...
Synchronize(FireMyEvent);

Would the above work?
0
The 14th Annual Expert Award Winners

The results are in! Meet the top members of our 2017 Expert Awards. Congratulations to all who qualified!

 
JimBob091197Commented:
Your code will work fine.

FMyEvent is private, so cannot be accessed from outside.  You can declare the event as a property like a normal component:

type
  TMyThread = class(TThread)
  private
    FMyEvent: TNotifyEvent;
    procedure FireMyEvent;
  public
    property MyEvent: TNotifyEvent read FMyEvent write FMyEvent;
    procedure Execute; override;
  end;

Your calling form could then set the event as follows:
  with TMyThread.Create(True) do begin
    MyEvent := DoMyThreadDone;
    Resume;
  end;

The form would then implement DoMyThreadDone:
procedure TForm1.DoMyThreadDone(Sender: TObject);
begin
  ShowMessage('Thread Done');
  // Note: The thread still exists at this point!!
  // Thus you can access it via "TMyThread(Sender)"
end;


Your "FireMyEvent" would remain unchanged...

JB
0
 
JimBob091197Commented:
Hi bcrotaz,

Did you come right with your thread events?

JB
0
 
bcrotazAuthor Commented:
Yup.

That's great, thanks.
0
All Courses

From novice to tech pro — start learning today.