Thread

I have a thread and I execute it by the help of a timer
which triggers at 1ms.

type
 TMyThread = class(TThread)
   procedure Execute; override;
   constructor Create; overload;
 end;

constructor TMyThread.Create;
begin
     inherited Create(False);
end;
.
.
.
var myt:MyThread;
.
.
.
myt:=MyThread.Create;
myt.Priority:=tpNormal;
.
.
.
myt.execute;
.
.
.
myt.Free;

Sometimes, when the program tries to create the thread
it fails and an error message is received. If I want to
create it again it also fails. But, sometimes it works
without any problem. It behaves like this for any code
in the thread's execute part. Am I doing something wrong
or is this because of something else? Can I correct
this? How? Should I make the thread in a different way?
If so, how can I do that? Please, help me.
MikeMonroeAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

mocartsCommented:
you don't need to call myt.Free; as thread is freed automatically when terminated or Execute completes..
0
robert_marquardtCommented:
You do not understand threads at all.
Calling myt.Execute is completely wrong. It is called automatically by MyThread.Create(False) or by a call to myt.Resume.
Using a 1 msec normal timer is also silly. You cannot get less than 10 msec from a normal timer.
Why do you use a timer at all? The thread runs on its own.
0
MikeMonroeAuthor Commented:
I am using a timer because I want to run the thread multiple times, without blocking the programs execution. It doesn't free automatically(I did it this way).
0
Cloud Class® Course: Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

Colin_DawsonCommented:
I've made a couple of adjustments to your code.  Give this a try.  Firstly, I've set the code so that the thread will auto free itself.  Secondly I've introduced a loop that will check to see if you've requested that the thread be terminated.

In order to stop this thread processing, simplly call  MyThread.Terminate It's then save to assume that the thread has been freed.

You should only ever need to create one thread for a task then add more information for that thread to process.



type
TMyThread = class(TThread)
  procedure Execute; override;
  constructor Create; overload;
end;

constructor TMyThread.Create;
begin
  inherited Create(True); //Creates the thread suspended.
  FreeOnTerminate := True;  //Tell the thread to free after completion of the execute method.
  Resume; //Set the thread going
end;

Procedure TMyThread.Execute;
Begin
  While Not Terminated Do
  Begin
    If WorkToDo Then
    Begin
      //Process your thread code here.
    End
    Else Sleep( 1 ); //Sleeps to a millisecond
  End;
End;
0
MikeMonroeAuthor Commented:
I still get errors like 'Out of system resources' or 'Invalid handle' or 'Access denied'. Maby they occur because the thread can not be created or accessed at certain times(that's why sometimes it works the first time and sometimes not, maybe). If I put the code in a timer it works, so it isn't the fault of the code in the thread, but the thread's fault.
0
robert_marquardtCommented:
Do you really want to start a thread each msec?
The thread only does a single task and then terminates?
Do you still call Execute? Use Resume!

If you use your above source then it cannot work because it is completely wrong.

If you use a single variable myt to hold the thread object then you will overwrite it on each newly created thread and you orphan any previously started thread.
You always free (and terminate) the last thread created. Since you do not wait for the thread to terminate you cause real problems.
You should set the threads to free themselves. It is no problem then to orphan them because you do not need to free it anymore.

What are the threads doing? Do they compete for resources?
0
MikeMonroeAuthor Commented:
Show me how you make threads and run them please. I think it's better than correcting my thread, to write a new one. So, I need the thread to run as long as the program runs. It's better if I can stop it and restart it.
0
robert_marquardtCommented:
type
  TMyThread = class(TThread)
  public
    SomeThreadVariable: Integer;
    procedure Execute; override;
  end;


procedure TYourForm.TimerTimer(Sender: TObject);
begin
  // best avoid a variable
  // we create the thread suspended
  with TMyThread.Create(True) do
  begin
    // since we soon lose track of the thread we let it free itself when finished
    FreeOnTerminate := True;
    // set thread specific variables before the thread runs
    SomeThreadVariable := 1;
    // let the thread run
    Resume;
  end;  
end;

procedure TMyThread.Execute;
begin
  // for safety reasons
  try
    // NO "while not Terminated do" loop here or the thread would never terminate
    DoSomething;
  except
    // catches all exceptions
  end;
end;

I doubt that the above setup will work if you start a thread each msec. If the thread needs longer than a msec to terminate then you will be flooded with threads and each thread will take even longer to terminate.
In the end your program will choke on the threads.

Can you tell what you want to achieve each msec?
I would assume that a better setup would be only to have a single thread which keeps a job list and your main program adds each msec a new job to the list.
0
MikeMonroeAuthor Commented:
I am scanning for some updates in my thread. That's why I need it to do the same thing(start scan, scan, stop scan, start again...) until the program finishes. So, I used the timer to start the thread as soon as it finished. That's why it was set up at 1 msec. It's like a procedure I want to call again as soon as it finishes. Using a timer or recursion wouldn't provide the best solution for my program, so that's why I need a thread.
0
mocartsCommented:
then write OnTerminate event handler for thread:
TForm1 = class(TForm)
..
  procedure FormCreate(Sender: TObject);
private
  procedure ThreadTerminated(Sender: TObject);
  procedure StartNewThread;
end;

implementation

procedure TForm1.StartNewThread;
begin
    with TMyThread.Create(True) do begin
      // set required properties
     OnTerminate := ThreadTerminated;
     Resume;
    end;
end;

procedure TForm1.ThreadTerminated(Sender: TObject);
begin
  // executes in context of main thread
  if not Application.Terminated {or some other flag} then
    StartNewThread;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  StartNewThread;
end;    

wbr, mo.
0
steve_hskCommented:
Hi Mike,

I guess it's just a different perspective, but I don't like the idea of continually starting and stopping 1000's of threads to do very small jobs. There are potentially lots of reasons why this is bad not least of all that your giving your app and the OS a massive amount of work thread switching, resource handling, and memory management to do when it is all unnecessary.

The only valid reason behind using threads to ensure that operations can happen supposedly simulataneously. I guess we need to know more about exactly what you're trying achieve. I'll suggest an idea that may be a little of the mark ... but it's better programming practice than to start and stop threads continusouly.

We'll work with two threads, master and slave, where the master will instruct the slave to undertake some work on a timer. After the slave has completed the work, it simply waits to be instructed for the next 'job'.

There are two basic window's technologies we'll use here, threads, and window's messages. The master creates the slave, which waits for a message from the master. On the timer operating within the master, we simple post a msg to the thread !

I use this method when writing extremely fast network decoders, that need to undertake 3000 network msg decodes per second, and I can assure you that it's fast, effective, simple, and not memory or CPU hungry :

// SLAVE CODE ...

UNIT Threadbase;
INTERFACE
USES Windows, Classes;

CONST WM_DO_STUFF_1 = WM_USER + 1001;
CONST WM_DO_STUFF_2 = WM_USER + 1002;

TYPE TThreadBase = CLASS (TThread)
PUBLIC    
     // Class Operating Internals
     CONSTRUCTOR Create;  VIRTUAL;
     DESTRUCTOR  Destroy; VIRTUAL;

     // Member Object Instances
     PROCEDURE Execute; OVERRIDE;
     PROCEDURE DecipherMessage (Msg : TMsg); VIRTUAL;
END;

IMPLEMENTATION

CONSTRUCTOR TThreadBase.Create;
BEGIN
     // Inherit parent properties :Create suspended
     INHERITED Create(TRUE);
     FreeOnTerminate := FALSE;
     Priority        := tpHigher;    
END;

DESTRUCTOR TThreadBase.Destroy;
BEGIN
     INHERITED DESTROY;
END;

PROCEDURE TThreadBase.Execute;
VAR Msg : TMsg;
BEGIN
    WHILE NOT (terminated) DO
    BEGIN
        dError := GetMessage(Msg,0,0,0);

        IF (dError = TRUE) THEN
        BEGIN
            DecipherMessage(Msg);

            WHILE (peekmessage(Msg,0,0,0,PM_REMOVE) = True) DO
            BEGIN
                DecipherMessage(Msg);
            END;
        END
        ELSE IF (dError = FALSE) THEN
        BEGIN
            // has received the WM_QUIT msg
            Terminate;
        END
        ELSE
        BEGIN
            // error has occurred : may wish to handle
            Terminate;
        END
    END;    
END;

PROCEDURE TThreadBase.DecipherMessage (Msg : TMsg);
BEGIN
     CASE Msg.MESSAGE OF

        WM_DO_STUFF_1 :
        BEGIN    
             // Do your operations here
        END;

        WM_DO_STUFF_2 :
        BEGIN    
             // Do your operations here
        END;
END;

// MASTER CODE ...

UNIT Unit1;
INTERFACE
USES Windows, Messages, Classes, Controls, Forms, Dialogs,
     StdCtrls, ExtCtrls, ComCtrls, Threadbase;

TYPE TForm1 = class(TForm)
PUBLISHED
    Button1  : TButton;
    Timer1   : TTimer;
    PROCEDURE FormCreate  (Sender: TObject);
    PROCEDURE Timer1Timer (Sender: TObject);
    PROCEDURE FormDestroy (Sender: TObject);
PRIVATE
    m_tSlave : TThreadBase;
END;

VAR Form1: TForm1;
IMPLEMENTATION
{$R *.DFM}

PROCEDURE TForm1.FormCreate(Sender: TObject);
BEGIN
    m_tSlave := TThreadBase.Create;
    m_tSlave.Resume;
    Timer1.Enabled := FALSE;
END;

PROCEDURE TForm1.Button1Click(Sender: TObject);
BEGIN
    Timer1.Enabled := NOT(Timer1.Enabled);
END;

PROCEDURE TForm1.Timer1Timer(Sender: TObject);
BEGIN
    // Insert any data you want the slave thread to have into Lparam() and Wparam() as below ...
    PostThreadMessage(m_tSlave.ThreadID,
                      WM_DO_STUFF_1,
                      WPARAM(0),  
                      LPARAM(0));
END;

PROCEDURE TForm1.FormDestroy(Sender: TObject);
BEGIN
    // Method 1:
    PostThreadMessage(m_tSlave.ThreadID,
                      WM_QUIT,
                      0,  
                      0);
   
    // Method 2:
    // m_tSlave.Terminate;

    Sleep(1000); // must give the thread a chance to end

    IF m_tSlave <> NULL THEN
    BEGIN
        m_tSlave.Free;
    END;
END;

Note : As robert_marquardt said, the TTimer object, although has msecs unit, only has  a 10 msec resolution. If you need anymore detailled code, or an example for a 1 msec timer, let me know, and I'll post a threaded example up.

So as (I hope) you can see from the code, we're not stopping and starting multiple threads, just one. When the threads got nothing to do, it waits on the GetMessage function call, until a msg arrives to action.

I hope this all makes sense.
STeve
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
MikeMonroeAuthor Commented:
For my application I just need to capture a certain part of the screen continuously. I know how to capture the screen, but this is a very intensive CPU activity. That's why I want to use a thread. The capture code has no problem. I just need to encapsulate it in a thread which should execute the capture continuously when I tell it to start and until I tell it to finish. I didn't use threads before, so I need an exact soure code sample of a thread that can do what I said. To steve_hsk: Your idea is interesting, but too complex for my program's needs. I think it can be done in a simpler way.
0
steve_hskCommented:
Mike,

I can appreciate that complexity is simply perspective when looking at a problem. This is of course your project and you must be completely comfortable with the coding methods and technologies that you use. I'll simply say that :-

1) For good programming practice, I think it would be a wise move to learn this fundamental method.
2) The code I listed for you is in full working order. All that you need to do is to insert your screen capture code into the following block :-

PROCEDURE TThreadBase.DecipherMessage (Msg : TMsg);
BEGIN
    CASE Msg.MESSAGE OF
       WM_DO_STUFF_1 :
       BEGIN    
            // Screen Capture code goes here !
       END;
END;

and I missed a variable declaration for dError here :

PROCEDURE TThreadBase.Execute;
VAR Msg : TMsg; dError : Boolean;

And this code should compile and work for you. I thought about making a fast threaded screen capture component for you, as we already have nearly all the code necessary, but the points aren't quite high enough for that ;-)

Good luck in finding a solution you feel happy with,
STeve
0
robert_marquardtCommented:
A thread will not help you to lower the CPU load. Quite the contrary.

This is a job where a thread is the silliest idea possible.
Capturing the screen in a timer without threads will work better. If the capturing needs more than a msec then a thread cannot help at all.
0
MikeMonroeAuthor Commented:
I am not using the thread to lower the CPU load, but to allow the program to continue executing while the capture takes place without using ProcessMessages.
0
mocartsCommented:
const
  iInterval = 100; // milliseconds
TMyThread.Execute;
var
 t: dword;
begin
  while not Terminated do begin
    if (GetTickCount - t) >= iInterval then
    begin
      CaptureScreen;
      // or before CaptureScreen, if you need more exact timing
      t := GetTickCount;
    end;
  end;
end;
0
CleanupPingCommented:
MikeMonroe:
This old question needs to be finalized -- accept an answer, split points, or get a refund.  For information on your options, please click here-> http:/help/closing.jsp#1 
EXPERTS:
Post your closing recommendations!  No comment means you don't care.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.