Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Как узнать, что TThread отработал


Автор: MadCoder 12.6.2008, 15:45
Здравствуйте!

Моя программа создает некоторое количество потоков (50 и более). Как программа может узнать, что код потоков отработал и можно продолжать другие действия.

Автор: Poseidon 12.6.2008, 15:50
Все зависет от того, как у тебя создаются и завершаются потоки. Можно периодично assigned проверять, можно в конце потока передавать "я завершаюсь" в основной (или в "проверяющий") поток. Тут на что фантазии хватит.

Автор: Rrader 12.6.2008, 15:55
WaitForMultipleObjects?

Автор: Alexeis 12.6.2008, 16:04
MadCoder, у TThread есть функция waitfor т.е. можно поджать завершения, а можно создать семафор, по выходу счетчик автоматом будет уменьшаться.

Автор: MetalFan 12.6.2008, 20:00
Цитата(Alexeis @  12.6.2008,  16:04 Найти цитируемый пост)
можно создать семафор, по выходу счетчик автоматом будет уменьшаться

сорь, о чем речь? ) по выходу из чего и как это автоматом?

Автор: Alexeis 12.6.2008, 20:09
Цитата(MetalFan @  12.6.2008,  19:00 Найти цитируемый пост)
сорь, о чем речь? ) по выходу из чего и как это автоматом?


  Перед стартом всех потоков нужно сигнализировать его нужное количество раз, а по выходу из потока занимать. Использовать как счетчик. 

Автор: MadCoder 12.6.2008, 21:00
Цитата(Alexeis @ 12.6.2008,  20:09)
Цитата(MetalFan @  12.6.2008,  19:00 Найти цитируемый пост)
сорь, о чем речь? ) по выходу из чего и как это автоматом?


  Перед стартом всех потоков нужно сигнализировать его нужное количество раз, а по выходу из потока занимать. Использовать как счетчик.

Т.е. так:
Код

var
A: Integer;
begin
for A:=0 to 50 do
Thread.Create;
while A<>0 do
Application.ProcessMessage;
// После завершения всех потоков делаем что-то дальше
DoSome(Thing);
ShowMessage('Все отработало');
end;


а в процедуре Execute потока писать:
Код

procedure Thread.Execute;
...
// Какие-то действия
DoThomeShing;
Dec(A);
end;


?

Автор: MetalFan 12.6.2008, 21:01
Alexeis, ну да, собстно в http://msdn.microsoft.com/en-us/library/ms686946.aspx есть хороший пример по этому поводуь

Автор: MadCoder 12.6.2008, 21:06
MetalFan, можешь написать примерчик на Делфи, очень надо, пожаааалуйста smile.

Автор: MetalFan 12.6.2008, 21:24
а что не понятно в примере из msdn?

Автор: Exai1e 12.6.2008, 21:33
MetalFan, мб синтаксис и "неизвестные" операторы ?) ;)

Автор: Rennigth 15.6.2008, 00:42
хм, забыли про OnTerminated smile  Если конечно потоки на основе TThread  smile 

Автор: MadCoder 20.6.2008, 14:18
Цитата(Rennigth @ 15.6.2008,  00:42)
хм, забыли про OnTerminated smile  Если конечно потоки на основе TThread  smile

Точно! Значит поток Terminate, в функции OnTerminated уменьшаем счетчик и в главном коде ставим:

Код

while counter<>0 do application.processmessages


Все ясно! Спасибо smile.

Автор: CodeMonkey 26.6.2008, 10:43
P.S.
Цитата(MadCoder @  20.6.2008,  14:18 Найти цитируемый пост)
Код
while counter<>0 do application.processmessages

Вообще-то это не даст выполняться Synchronize и вообще цикл будет постоянно крутиться (хотя, возможно что в вашей ситуации это не важно). Я бы использовал HandleMessage и после уменьшения счётчика пробуждал бы главный поток отправкой WM_NULL. 

Автор: MadCoder 3.7.2008, 10:56
Код

var
A: Integer;
Thread: TThread;
Handles: array of cardinal;
begin
SetLength(Handles, 1000);
for A:=0 to 999 do
with Thread.Create(False) do
Handles[A]:=Handle;
if waitformultipleobjects ( Length(Handles), @Handles, true, infinite) = 1 then
ShowMessage('Потоки отработали');


Так?

Автор: MadCoder 6.7.2008, 00:10
Не работает smile 

Автор: Rrader 6.7.2008, 07:13
Код

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TMyThread = class(TThread)
  protected
    procedure Execute; override;
  end;  

var
  Form1: TForm1;
  A: Integer = 0;

implementation

{$R *.dfm}

{ TMyThread }

procedure TMyThread.Execute;
begin
  Sleep(50);
  InterlockedIncrement(A);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Handles: array [1..MAXIMUM_WAIT_OBJECTS] of THandle;
  I: Integer;
begin
  A := 0;
  for I := Low(Handles) to High(Handles) do
    with TMyThread.Create(False) do
    begin
      Handles[I] := Handle;
      { Лучше заменить на массив потоков }  
      //FreeOnTerminate := True;
    end;
  if WaitForMultipleObjects(High(Handles),
    @Handles, True, INFINITE) = WAIT_OBJECT_0 then ShowMessage(IntToStr(A));
  ShowMessage(SysErrorMessage(GetLastError));
end;

end.

Цитата(MSDN)

WaitForMultipleObjects
Parameters
nCount
Specifies the number of object handles to wait for in the array pointed to by lpHandles. The maximum number of object handles is MAXIMUM_WAIT_OBJECTS. 


Однако данная функция очень удобна и атомарна в своих действиях, поэтому я бы сделал несколько серий ожиданий.

Автор: MadCoder 8.7.2008, 14:26
Сделал копи-паст полный, скомпилировал, запускаю, пишет: "Параметр задан неверно" и "Неверный дескриптор".

Автор: Rennigth 8.7.2008, 14:58
MadCoder, 
Успевали первые треды завершиться до вызова W@aitForMultipleObjects.
Если переделать примерно так, то работает.
Код

unit Unit34;

interface

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

type
  TForm34 = class(TForm)
    btn1: TButton;
    procedure btn1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TMyThread = class(TThread)
  protected
    procedure Execute; override;
  end;

var
  Form34: TForm34;
  A: Integer = 0;

implementation

{$R *.dfm}

{ TMyThread }

procedure TMyThread.Execute;
begin
  Sleep(50);
  InterlockedIncrement(A);
  Sleep(1000);
end;

procedure TForm34.btn1Click(Sender: TObject);
var
  Handles: array [1..MAXIMUM_WAIT_OBJECTS] of THandle;
  I: Integer;
  WaitRes: Cardinal;
begin
  SetLastError(NO_ERROR);
  A := 0;
  for I := Low(Handles) to High(Handles) do
    with TMyThread.Create(True) do
    begin
      Handles[I] := Handle;
      Resume;
      FreeOnTerminate := True;
    end;
  WaitRes := WaitForMultipleObjects(High(Handles),
    @Handles, True, INFINITE);
  if WaitRes = WAIT_OBJECT_0 then
    ShowMessage(IntToStr(A))
  else
    ShowMessage(SysErrorMessage(GetLastError));
end;

end.


Автор: Rrader 8.7.2008, 15:06
Ага, нашел ошибку. Из-за FreeOnTerminate  smile 

Автор: MadCoder 8.7.2008, 16:51
Спасибо, супер smile 

Автор: Rrader 8.7.2008, 17:21
MadCoder, в таком случае, чтобы без FreeOnTerminate работать, заведи еще и массив потоков. Создавай их так же, но в конце удаляй (Free). Иначе получаешь утечку памяти...неслабую

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)