After OnTerminate TThread

0

Mam pytanko. Gdy uruchomimy kilka podobnych wątków

  if lvDevice.Items.Count >0 then
  begin
    for i := 0 to lvDevice.Items.Count - 1 do
      if lvDevice.Items[i].Selected then
        for j := 0 to Length(device) - 1 do
          if (lvDevice.Items[i].Caption = device[j].nazwa) then
            TWatekOdblokuj.Create(j, i, blok);

Na koncu mam

procedure TWatekOdblokuj.WatekOnTerminate(Sender: TObject);
begin
  Synchronize(OdblokujUsera);
end;

Po zakończeniu WSZYSTKICH wątków potrzebuję wykonać pewną procedurę niestety wstawienie jej po Synchronize wywołuje AccessViolation. Moje pytanie JAK wychwycić moment zakończenia wszystkich wątków?

0

Nie wiem czy jest inne rozwiązanie i prostsze - pewnie tak, ale ja wpadłem na coś takiego jak poniżej. Sprawdziłem i działa,
ale nie wiem czy o takie coś Tobie chodziło. Poniżej kod jakby link, ktory jest od czasu ostatniego pobrania aktywny siedem
dni - wygasł, a ktoś by miał podobny problem i trafił na ten - nomen omen - wątek :) A całe źródło jest pod tym adresem:
http://www.speedyshare.com/files/22798861/threads_4.rar

unit Unit1;

interface

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

type
  TMainForm = class(TForm)
    LogMemo : TMemo;
    ThrStartBtn : TButton;
    procedure FormCloseQuery(Sender : TObject; var CanClose : Boolean);
    procedure FormCreate(Sender : TObject);
    procedure ThrStartBtnClick(Sender : TObject);
  private
  public
    ThrList : TList;
    ActiveThr : TThread;
    procedure ThrTerminate(Sender : TObject);
  end;

  TThr = class(TThread)
  private
    FSleepTime : Cardinal;
  protected
    procedure Execute; override;
  public
    constructor Create(SleepTime : Cardinal);
  end;

var
  MainForm : TMainForm;

implementation

{$R *.dfm}

procedure TThr.Execute;
begin
  with MainForm do
  begin
    Self.OnTerminate := ThrTerminate;
    Sleep(FSleepTime);
  end;
end;

constructor TThr.Create(SleepTime : Cardinal);
begin
  inherited Create(False);
  FSleepTime := SleepTime;
end;

procedure TMainForm.ThrTerminate(Sender : TObject);
var
  Idx : integer;
begin
  Idx := ThrList.IndexOf(Sender);
  ThrList.Delete(Idx);
  LogMemo.Lines.Delete(Idx);
  if ThrList.Count = 0 then
  begin
    MessageBox(Application.Handle, PChar('Wszystkie wątki zostały zakończone.'),
      PChar(Application.Title), MB_OK + MB_ICONINFORMATION);
    ThrStartBtn.Enabled := True;
  end;
end;

procedure TMainForm.FormCloseQuery(Sender : TObject; var CanClose : Boolean);
begin
  ThrList.Free;
end;

procedure TMainForm.FormCreate(Sender : TObject);
begin
  Randomize;
  LogMemo.Clear;
  ThrList := TList.Create;
  LogMemo.ReadOnly := True;
  Application.Title := Caption;
  LogMemo.ScrollBars := ssVertical;
end;

procedure TMainForm.ThrStartBtnClick(Sender : TObject);
var
  I : integer;
  R : Cardinal;
begin
  ThrStartBtn.Enabled := False;
  for I := 1 to 20 do
  begin
    R := Random(10000) + 1000;
    LogMemo.Lines.Add(Format('Wątek numer: %.2d - będzie istniał przez: ' +
      '%d milisekund(y)', [LogMemo.Lines.Count + 1, R]));
    ActiveThr := TThr.Create(R);
    ThrList.Add(ActiveThr);
  end;
end;

end.
0
woolfik napisał(a)

Po zakończeniu WSZYSTKICH wątków potrzebuję wykonać pewną procedurę niestety wstawienie jej po Synchronize wywołuje AccessViolation. Moje pytanie JAK wychwycić moment zakończenia wszystkich wątków?

  • możesz na koniec pracy wątku wysłać message do głównego wątku, i zliczać te komunikaty
  • możesz użyć WaitForMultipleObjects
  • możesz użyć rozwiązania opartego na liczniku (pamiętaj o synchronizacji dostępu do niego)
  • możesz użyć TThreadList

Aha, chyba w procedurze wywoływanej w OnTerminate nie musisz używać Synchronize. Zerknij do kodu TThread.

b

0

Dzięki Panowie najbardziej proste wydało mi się rozwiązanie z dodaniem licznika i poki co działa bez zarzutu. Browar dla was

1 użytkowników online, w tym zalogowanych: 0, gości: 1