Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

URGENT: Problem with threads

Posted on 2004-10-25
9
Medium Priority
?
641 Views
Last Modified: 2010-04-05
I have input file - plain text in the format:
1
2
3
...

I use this file for open URL, submit the value as a parameter, retrieve some info and save it to file. I use a dynamic array of TMyThread type. Let's say I set its length to 30. Then loop through Low() and High() and check if the element is nil - create the thread. If it is not - check if it is running (public var in the thread). I set FreeOnTerminate = True, but somehow the thread is not nil after it finished.

I the loop if the thread has finished (it should be nil because FreeOnTerminate = True) I create a new instance. But Somehow the finished thread is not nil... I create it with CreateSuspended = False...
0
Comment
Question by:Ivanov_G
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 3
  • 2
  • +1
9 Comments
 
LVL 6

Expert Comment

by:vadim_ti
ID: 12400077
FreeOnTerminate only destroy thread, but will not assign nil  to thread variable,
you can nil array element in onDestroy method of your thread
0
 
LVL 6

Expert Comment

by:vadim_ti
ID: 12400125
think abot it, you can save Thread object in number of different variables, thread could not to nil them (and even to know
about them)
but in your on destory event you can loop through your array
for (....) {
  if (ThreadArr[i] = Self) then begin
     ThreadArr[i] := nil;
     break;
  end
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 12400221

It would actually be better to set the OnTerminate method handler for the thread, as this will run in the context of the main thread.

OnTerminate
---------------
Occurs after the thread's Execute method has returned and before the thread is destroyed.

property OnTerminate: TNotifyEvent;

Description

Write an OnTerminate event handler to execute code after the thread finishes executing. The OnTerminate event handler is called in the context of the main VCL thread, which means VCL methods and properties can be called freely. The thread object may also be freed within the event handler.


---

Regards,
Russell
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 12

Author Comment

by:Ivanov_G
ID: 12400452
I think I have to clarify few things

type
   ThreadArr     : array of TMyThread;

    for counter := Low(ThreadArr) to High(ThreadArr) do
      begin
        if ThreadArr[counter] = nil then
          begin
            if InputStrings.Count > 0 then
              begin
                ThreadArr[counter] := TMyThread.Create(False, ThreadOptions, InputStrings[0]);
                InputStrings.Delete(0);
              end;
          end
        else
          if ThreadArr[counter].IsFinished then
            begin
              ThreadArr[counter].Terminate;
              ThreadArr[counter] := nil;
            end;
      end;

This is the case here... Is finished is public variable in the thread which shows me if everything with the HTTP ended correctly...
0
 
LVL 6

Assisted Solution

by:vadim_ti
vadim_ti earned 400 total points
ID: 12400538
if from any reason your execute method will be finished before you will check
   ThreadArr[counter].IsFinished
you are in troubles.

i think safer place for nilling ThreadArr[counter] is in thread destructor or in finally part of thread execute method
(if you can be sure never exceprion will be raised in Thread constructor)

on the safe side you can protect ThreadArr via critical section.
0
 
LVL 26

Accepted Solution

by:
Russell Libby earned 1600 total points
ID: 12400741
I agree with part of the above statement.

>> if from any reason your execute method will be finished before you will check
   ThreadArr[counter].IsFinished
you are in troubles.


The IsFinished is a public variable of the thread, but the thread is set to "free on terminate", so if it frees itself when done, then the context of this variable is no longer valid.

---

I would not try to access the main thread from the thread destructor though, but would use the OnTerminate event to handle this:

eg:

type
  ThreadArr     : array of TMyThread;

  for counter := Low(ThreadArr) to High(ThreadArr) do
  begin
     if (ThreadArr[counter] = nil) then
     begin
        if InputStrings.Count > 0 then
        begin
           try
              ThreadArr[counter]:=TMyThread.Create(False, ThreadOptions, InputStrings[0]);
              InputStrings.Delete(0);
           finally
              ThreadArr[counter].OnTerminate:=OnMyThreadTerminate;
           end;
        end;
     end
     else
        // Terminate the thread (it will clean itself up
        ThreadArr[counter].Terminate;
  end;

  // Replace TForm1 with whatever your main object class is
  TForm1.OnMyThreadTerminate(Sender: TObject);
  begin
     // Walk the list
     for counter:=Low(ThreadArr) to High(ThreadArr) do
     begin
        // Check indexed thread with sender
        if (ThreadArr[counter] = Sender) then
        begin
           // Found item, nil out and break loop
           ThreadArr[counter]:=nil;
           break;
        end;
     end;
  end;

--

This will allow you to clear the thread list from within the main thread, which is where it **should** be done. If you wish to access threadarr variable from the Thread's destructor then the use of a mutex/critical section would be MANDATORY.

One side note to this. The execute method of the thread should be written to periodically check the Terminated property. From the help file:

Indicates whether the thread has been asked to terminate.

property Terminated: Boolean;

Description

The thread's Execute method and any methods that Execute calls should check Terminated periodically and exit when it's True.. The Terminate method sets the Terminated property to True.

The Terminate method is the polite way to abort the execution of a thread, but it requires cooperation from the thread’s Execute code. Using terminate is recommended over the TerminateThread Win32 API call.

eg:

procedure TMyThread.Execute;
var finished: Boolean;
begin

 while not(Finished) and not(Terminated) do
 begin
       ....
      // Set finished when finished
 end;

end;

or

procedure TMyThread.Execute;
begin



end;


------------

Russell
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 12400754
Oops, posted too quick...

another example of execute without looping

procedure TMyThread.Execute;
begin

  // perform first step
  ....

  if not(Terminated) then
  begin
     //  next step
     ....
     if not(Terminated) then
     begin
        // next step
        ....
        etc....
     end;
  end;

end;

----
Regards,
Russell
0
 
LVL 12

Expert Comment

by:Lee_Nover
ID: 12408101
weird pooling scheme if it is ment to be one
for a thread pool check for example Indy's ThreadPool
the threads that finish just get suspended .. when needed nonworking threads get returned, if no thread is free a new one is created
think of something in the lines of:
while InputStrings.Count > 0 do
begin
  thd:=ThreadPool.GetAvailableThread(true {allow create});
  thd.ProcessURL(InputStrings[InputStrings.Count-1]);
  InputStrings.Delete(InputStrings.Count-1);
end;

with proper locking you could make this 'live' :)
0
 
LVL 12

Author Comment

by:Ivanov_G
ID: 12411207
somehow ... some of the thread fails. If I run it once, it can finish successfully, but the second time, some thread will fail and this will stop the whole application...

I am trying to debug this now, but with so many threads ... grrr
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Want to learn how to record your desktop screen without having to use an outside camera. Click on this video and learn how to use the cool google extension called "Screencastify"! Step 1: Open a new google tab Step 2: Go to the left hand upper corn…
Please read the paragraph below before following the instructions in the video — there are important caveats in the paragraph that I did not mention in the video. If your PaperPort 12 or PaperPort 14 is failing to start, or crashing, or hanging, …
Suggested Courses

609 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question