unit TThreadListList;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

// BeginExample: TThreadList
// Method: Classes.TThreadList.LockList
// Method: Classes.TThreadList.UnlockList
// Method: Classes.TThreadList.Add
// Method: Classes.TThreadList.Remove
// Method: Classes.TThread.Terminate
// Property: Classes.TThread.Terminated

// BeginCode
{
The following example shows how to use the LockList and
UnlockList methods to access a thread-safe version  of a
TList object:
}
type
  TForm1 = class(TForm)
    Button1: TButton;
    Button3: TButton;
    ListBox1: TListBox;
    Button2: TButton;
    Button4: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
  TListThread = class(TThread)
  protected
    procedure Execute; override;
  end;
  TMyThread = class(TThread)
  protected
    procedure Execute; override;
  end;
  TYouThread = class(TThread)
  protected
    procedure Execute; override;
  end;

var
  Form1: TForm1;
  threadList1: TThreadList;
  mythreadRunning, youthreadRunning, listThreadRunning: Boolean;
  globalCount: Integer;
  listProcess: TListThread; { TListThread is a custom descendant of TThread }
  secondProcess: TMyThread; { TMyThread is a custom descendant of TThread }
  otherSecondProcess: TYouThread; { TMyThread is a custom descendant of TThread }

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  if (mythreadRunning = FALSE) then
  begin
    mythreadRunning:= TRUE;
    secondProcess := TMyThread.Create(True); { create suspended – secondprocess does not run yet }
    secondProcess.FreeOnTerminate := True; { don't need to cleanup after terminate }
    secondProcess.Priority := tpLower;  // set the priority to lower than normal
    secondProcess.Resume; { now run the thread }
  end
  else
    MessageDlg('This thread is still running.  You are going to hurt yourself!',
      mtInformation, [mbOk], 0);
end;

procedure TMyThread.Execute;
var
  I: Integer;
  myRadio: TRadioButton;
begin
  for I := 0 to 20 do
  begin
    if (Terminated) then
    begin
      mythreadRunning:= FALSE;
      exit;
    end;
    myRadio:= TRadioButton.Create(Form1);
    globalCount:= globalCount + 1;
    myRadio.Name:= 'RadioButton' + IntToStr(globalCount);
    threadList1.Add(myRadio);
    Sleep(1000);
  end;
  mythreadRunning:= FALSE;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if (listthreadRunning = FALSE) then
  begin
    listThreadRunning:= TRUE;
    listProcess := TListThread.Create(True); { create suspended – secondprocess does not run yet }
    listProcess.FreeOnTerminate := True; { don't need to cleanup after terminate }
    listProcess.Priority := tpLower;  // set the priority to lower than normal
    listProcess.Resume; { now run the thread }
  end;
end;

procedure TListThread.Execute;
var
  I: Integer;
  Temp: TControl;
  myList: TList;
begin
  while(True) do
  begin
    if (Terminated) then
    begin
      listthreadRunning:= FALSE;
      exit;
    end;
    Form1.ListBox1.Clear;
    myList:= threadList1.LockList;
    try
      for I := 0 to myList.Count-1 do
      begin
        Temp:= myList.Items[I];
        Form1.ListBox1.Items.Add(Temp.Name);
      end;
    finally
      threadList1.UnlockList;
    end;
    Sleep(1000);
  end;
  listthreadRunning:= FALSE;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  if (youthreadRunning = FALSE) then
  begin
    youthreadRunning:= TRUE;
    otherSecondProcess := TYouThread.Create(True); { create suspended – secondprocess does not run yet }
    otherSecondProcess.FreeOnTerminate := True; { don't need to cleanup after terminate }
    otherSecondProcess.Priority := tpLower;  // set the priority to lower than normal
    otherSecondProcess.Resume; { now run the thread }
  end
  else
    MessageDlg('This thread is still running.  You are going to hurt yourself!',
      mtInformation, [mbOk], 0);
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  if (listProcess <> nil) then
    listProcess.Terminate;
  if (secondProcess <> nil) then
    secondProcess.Terminate;
  if (otherSecondProcess <> nil) then
    otherSecondProcess.Terminate;
end;

procedure TYouThread.Execute;
var
  I: Integer;
  Temp: TControl;
begin
  for I := 0 to 10 do
  begin
    if (Terminated) then
    begin
      youThreadRunning:= FALSE;
      exit;
    end;
    with threadList1.LockList do
    try
      if (2*I < Count) then
      begin
        Temp:= Items[2*I];
        threadList1.Remove(Temp);
      end;
    finally
      threadList1.UnlockList;
    end;
    if (Terminated) then
      MessageDlg('youThread has been asked to terminate, but is still running!',
        mtInformation, [mbOk], 0);
    Sleep(3000);
  end;
  youthreadRunning:= FALSE;
end;
// EndCode
// EndExample: TThreadList

procedure TForm1.FormCreate(Sender: TObject);
var
  RadioButton: TRadioButton;
  I: Integer;
begin
  mythreadRunning:= FALSE;
  youthreadRunning:= FALSE;
  listthreadRunning:= FALSE;
  listProcess:= nil;
  secondProcess:= nil;
  otherSecondProcess:= nil;
  threadList1:= TThreadList.Create;
  for I := 1 to 5 do
  begin
    RadioButton:= TRadioButton.Create(Form1);
    RadioButton.Name:= 'RadioButton' + IntToStr(I);
    threadList1.Add(RadioButton);
  end;
  globalCount:= 5;
end;

procedure TForm1.FormDestroy(Sender: TObject);
var
  I: Integer;
  Temp: TControl;
  myList: TList;
begin
  myList:= threadList1.LockList;
  try
    for I := 0 to myList.Count-1 do
    begin
      Temp:= myList.Items[I];
      Temp.Free;
    end;
  finally
    threadList1.UnlockList;
  threadList1.Free;
  end;
end;

end.
