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


Автор: sunnmas 3.8.2009, 14:54
Есть поток 1, который запускает множество потоков 2 и только и делает, что следит за состоянием этих, запущенных им потоков 2. Эти потоки 2 завершают свою работу и разлагаются)). Таких потоков 2 может быть ограниченное число (определяется пользователем). 
Вопрос: как узнать что потоки 2 уже заканчивают свою работу, чтобы запускать новые?

Код

Поток 1:
цикл
  Если потоков мало то
    создать нужн. кол-во потоков
    запоминаем на них ссылки в списке
    фриОнТерминатед = тру
    запустить потоки
  конецесли

  Здесь нужно вычислить сколько потоков из списка завершились, 
  т.е. узнать на сколько потоков стало меньше. Как?
  
конеццикла

Автор: Romikgy 3.8.2009, 15:34
OnTerminate

Автор: sunnmas 3.8.2009, 15:40
Поток 1 не главный поток не ВЦЛЬ. ОнТерминате выполняется в главном потоке. Так не нужно

Автор: Romikgy 3.8.2009, 17:24
через что создаются потоки тогда ? код покажи 

Автор: sunnmas 3.8.2009, 17:47
Код

unit TaskManager;

interface
uses Classes, Messages, RegThread, WordSet;

type TThreadTask = (Reg,Confirm,GetCategory,AddNew);

type TTaskManager = class(TThread)
  private
    RegThrLst: TList;

    NumRegThread: byte;

    HandleSet: TWordSet;
  public
    constructor Create(CreateSuspended: Boolean);
    destructor Destroy;
    procedure Execute; override;
end;
implementation

uses Main;

{ TTaskManager }

constructor TTaskManager.Create(CreateSuspended: Boolean);
begin
  inherited Create(CreateSuspended);
  NumRegThread:=0;

  RegThrLst:=TList.Create;

  HandleSet:=TWordSet.Create(20);
end;

destructor TTaskManager.Destroy;
begin
  RegThrLst.Destroy;
end;

procedure TTaskManager.Execute;
var RegThrd: TRegThread;
    i: integer;
begin
  inherited;
  while not Terminated do
  begin
    if NumRegThread<MainForm.RegNmThr then
    begin
      RegThrd:=TRegThread.Create(true,HandleSet.MinAbsentInSet);
      HandleSet.Add(HandleSet.MinAbsentInSet);
      RegThrLst.Add(RegThrd);
      NumRegThread:=NumRegThread+1;
      RegThrd.FreeOnTerminate:=true;
      RegThrd.Resume;
    end;
    for i:=0 to RegThrLst.Count-1 do
    begin
[size=10] [color=crimson]     if TRegThread(RegThrLst.Items[i]).Suspended then
      begin
        HandleSet.Sub(TRegThread(RegThrLst.Items[i]).ThreadHandle);
        TRegThread(RegThrLst.Items[i]).Destroy;
        RegThrLst.Delete(i);
        NumRegThread:=NumRegThread-1;[/color][/size]
      end;
    end;
  end;
end;

end.


картинка во вложении. Цветом выделен блок, которым я проверяю окончание работы потоков2

Автор: Alexeis 3.8.2009, 19:51
  У каждого Thread есть функция waitfor, которая будет ожидать завершения потока. Ее можно вызвать из любого потока.

Автор: MetalFan 3.8.2009, 21:40
sunnmas, ой жесть какая... может стоит сначала книжки умные почитать прежде, чем чушь городить?

Добавлено через 6 минут и 56 секунд
1. деструктор у наследника TThread не перекрыт. вызов метода Destroy предка соотв. не происходит.
2. Зато перекрыт метод Execute, что нафиг не нужно)
3. в делфи не принято вызывать напрямую Destroy, для этого есть метод Free.
4. второй цикл в Execute бредовый... словишь AV или List Index out of bound легко.
5. зачем NumRegThread, если есть RegThrLst.Сount ?
....
N. лучше иногда книжки почитать, чем что-то писать...

Автор: sunnmas 3.8.2009, 23:33
Согласимся с тем что олень, но не перестанем бицца)

Отступим назад. Вот пример приложения очень простого. Откуда там беруться глюки? Просвятите пожалуйста

Автор: atomAltera 4.8.2009, 03:35
можно и 
Код

postMessage(mainThread.handle, WM_USER+666, subThread.handle, 0)
 в конце каждого суб потока юзать... 

Автор: MetalFan 4.8.2009, 08:00
atomAltera, а нельзя. по крайней мере так. да, синхронизация с пом.сообщений возможна, но только лучше таки книжку почитать, или очень хорошую статью на этом форуме...

Автор: Alexeis 4.8.2009, 09:32
atomAltera, между последней строчкой потока и окончанием его жизни есть разница. По идее в момент отправки сообщения поток еще жив. Реально узнать о его завершении через хэндл можно вызвав WaitForSingleObject и дождавшись когда винда сама скажет - "да поток завершен, все его ресурсы освобождены". 

Автор: Romikgy 4.8.2009, 10:37
при использовании 


Цитата(sunnmas @  3.8.2009,  16:47 Найти цитируемый пост)
FreeOnTerminate:=true;

могу придложить такой вариант 
Код

 mythread = class(TThread)
  private
    { Private declarations }
    fhnd: Pointer;

  protected
   ...
    destructor Destroy; override;

    public
     procedure setclass( x: Pointer );
  end;

destructor mythread.Destroy;
begin

  inherited;
  if fhnd<>nil then
  TObject(fhnd^):=nil;
end;

procedure mythread.setclass(x: Pointer);
begin
 fhnd:=x;
end;


создание объекта изменится чуть 
Код

t:=mythread.Create(True);
  t.setclass(@t);
t.FreeOnTerminate:=True;
      t.Resume;

и проверка на убит процесс или нет 
Код

if Assigned(t) then

если поток автоубился значит процедуру ассигн он не пройдет ,
smile 
жду критики .....

Автор: MetalFan 4.8.2009, 14:27
Romikgy, 
ничего конечно идея, но, имхо, потокоНЕбезопасно...

Автор: Alexeis 4.8.2009, 14:44
Цитата(MetalFan @  4.8.2009,  13:27 Найти цитируемый пост)
ничего конечно идея, но, имхо, потокоНЕбезопасно...

  Почему же? Операция присвоения атомараная. Только вот негибко и не прозрачно. По моему если тебе важен момент завершения, то зачем делать FreeOnTerminate ? Классическая схема состоит в том чтобы вызвать у потока метод Terminate, который выставляет флаг Terminated в true. Правильный поток должен периодически проверять этот флаг и после установки его в true максимально быстро выйти из основного цикла. Поток вызвавший Terminate сразу же вызывает WaitFor и дожидается смерти потока(короткое время), после чего он может получить все необходимые финальные данные из убитого потока, после чего вызвать ему безопасно free; 
  Если же потоки часто создаются и уничтожаются то это неправильная политика, потому что неэффективная. Ненужный поток легко приостанавливается эвенте, после чего перестает потреблять процессорное время и в нужный момент может сразу же приступить к новой задаче, для этого достаточно будет поставить ему новую задачу (потокобезопасно ведь поток спит на эвенте) переключить эвент в активное состояние и ждать завершения работы, после чего поток можно снова усыпить на эвенте до появления новой задачи. 
  Т.о. вопросы уничтожения потоков появляются только по завершению работы программы один раз. Тут важно завершить связанные потоки их в правильной последовательности.

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