Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7557441
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 30, 20262026-05-30T12:07:55+00:00 2026-05-30T12:07:55+00:00

I’m writing a custom thread which includes some added functionality. The part I’m confused

  • 0

I’m writing a custom thread which includes some added functionality. The part I’m confused about is how to handle the Execute procedure, while still expecting it to be descended into more inherited implementations.

My custom thread is overriding the Execute procedure and adding some of my own stuff, such as events OnStart, OnStop and OnException, as well as looping capabilities. I’m not sure how to design this in a way that expects it to be further used in a further inherited thread.

How do I make it possible to further inherit this custom thread while maintaining the Execute functionality?

Here’s the execute procedure as I have overridden it…

procedure TJDThread.Execute;
begin
  Startup;
  try
    while not Terminated do begin
      if assigned(FOnExecute) then
        FOnExecute(Self);
      if not FRepeatExec then
        Terminate
      else
        if FExecDelay > 0 then
          Sleep(FExecDelay);
    end;
  finally
    Cleanup;
  end;
end;

I’m intending for FOnExecute to be actually an event of the thread, which is more-so a replacement of inheriting the Execute procedure – similar to how a service works. I don’t think this is the right way to go… How do I make sure this is coded in a safe manner? I’m open to suggestions to another approach than an event – so long as it’s aimed at the goal of making a custom TThread which can be inherited and further executed.

This custom thread I’m making includes some additional capabilities which don’t come with the original TThread and yet will be extremely useful for many future projects. The additional capabilities are specifically OnStart and OnStop events (similar to how a service works), CoInitialize built in (and only used if told to, default = false), Repeated execution (default = false), and delay between executions (default = 0).

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-30T12:07:57+00:00Added an answer on May 30, 2026 at 12:07 pm

    I agree with Rob. Don’t use an event, use a virtual method. But even if you were to use the event and employ its “assignedness” to signal whether there is work to be done, you would need to protect the FOnExecute member as it can be set from different threads.

    In one of our thread classes we use commands to do something similar:

    procedure TCommandThread.SetCommand(const Value: ICommand);
    begin
      Lock;
      try
        Assert(not IsAvailable, 'Command should only be set AFTER the thread has been claimed for processing');
    
        FCommand := Value;
    
        if Assigned(FCommand) then
          MyEvent.SetEvent;
      finally
        Unlock;
      end;
    end;
    

    As SetCommand (the Command’s setter) can be called from any ol’ thread, setting the FCommand member is protected by the thread’s critical section which is locked and unlocked through the Lock and Unlock methods.

    Signalling MyEvent is done because our thread class uses a TEvent member to wait for work.

    procedure TCommandThread.Execute;
    begin
      LogDebug1.SendFmtMsg('%s.Execute : Started', [ClassName]);
    
      // keep running until we're terminated
      while not Terminated do
      try
        // wait until we're terminated or cleared for take-off by the threadpool
        if WaitForNewCommand then
          if  Assigned(FCommand)
          and not Terminated then
            // process the command if we're told to do so
            CommandExecute;
    
      except
        LogGeneral.SendFmtError('%s.Execute : Exception occurred :', [ClassName]);
        LogGeneral.SendException;
      end;
    
      LogDebug1.SendFmtMsg('%s.Execute : Finished', [ClassName]);
    end;
    

    WaitForNewCommand returns when the MyEvent is signalled. This is done when a command is assigned, but also when a (running) command is cancelled, when the thread is terminated etc. Note that Terminated is checked again just before CommandExecute is called. This is done because when WaitForNewCommand returns, we could be in a situation where both a command was assigned and terminate has been called. After all, signalling the event can be done twice from different threads and we don’t know when or in what order anything happened.

    CommandExecute is a virtual method that different thread classes can override. In the default implementation it provides for all the status processing around command execution so the commands themselves can concentrate on their own stuff.

    procedure TCommandThread.CommandExecute;
    var
      ExceptionMessage: string;
    begin
      Assert(Assigned(FCommand), 'A nil command was passed to a command handler thread.');
      Assert(Status = chsIdle, 'Attempted to execute non-idle command handler thread');
    
      // check if the thread is ready for processing
      if IsAvailable then // if the thread is available, there is nothing to do...
        Exit;
    
      try
        FStatus := chsInitializing;
        InitializeCommand;
    
        FStatus := chsProcessing;
        try
          ExceptionMessage := '';
          CallCommandExecute;
        except
          on E: Exception do begin
            ExceptionMessage := E.Message;
            LogGeneral.SendFmtError('%s.CommandExecute: Exception occurred during commandhandler thread execution:', [ClassName]);
            LogGeneral.SendException;
          end;
        end;
    
      finally
          FStatus := chsFinalizing;
          FinalizeCommand;
    
          FStatus := chsIdle;
          FCommand := nil;
    
          // Notify threadpool we're done, so it can terminate this thread if necessary :
          DoThreadFinished;
    
          // Counterpart to ClaimThreadForProcessing which is checked in IsAvailable.
          ReleaseThreadForProcessing; 
      end;
    end;
    

    CallCommandExecute is where, through several levels of indirection the FCommand’s Execute method is called and where the real work of the command is done. That is why that call is directly protected with a try-except block. Other than that each Command in and of itself is responsible for thread safety with regard to the resources it uses.

    ClaimThreadForProcessing and ReleaseThreadForProcessing are used to claim and release a thread. For speed’s sake they don’t use the thread’s lock, but use the interlocked mechanism to change the value of the class’ FIsAvailable member which is declared as a pointer and used as a boolean:

    TCommandThread = class(TThread)
      // ...
      FIsAvailable: Pointer;
    
    function TCommandThread.ClaimThreadForProcessing: Boolean;
    begin
      Result := Boolean(CompatibleInterlockedCompareExchange(FIsAvailable, Pointer(False), Pointer(True)));
      // (See InterlockedExchange help.)
    end;
    
    function TCommandThread.ReleaseThreadForProcessing: Boolean;
    begin
      FIsAvailable := Pointer(True);
      Result := IsAvailable;
    end;
    

    If any of the “finally” processing in the CommandExecute method needs to be done regardless of exceptions raised by other calls in that process, you will have to use nested try-finally’s to ensure that is the case. The above method was simplified from our real code and the actual finally block is a set of nested try finally’s to ensure that DoThreadFinished etc. get called regardless of exceptions in FinalizeCommand (and other calls in between).

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

link Im having trouble converting the html entites into html characters, (&# 8217;) i
I have just tried to save a simple *.rtf file with some websites and
For some reason, after submitting a string like this Jack’s Spindle from a text
I am trying to understand how to use SyndicationItem to display feed which is
I used javascript for loading a picture on my website depending on which small
I have a string like this: La Torre Eiffel paragonata all’Everest What PHP function
I am reading a book about Javascript and jQuery and using one of the
I'm parsing an RSS feed that has an ’ in it. SimpleXML turns this
I have a text area in my form which accepts all possible characters from
I am writing an app with both english and french support. The app requests

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.