powered by simpleCommunicator - 2.0.59     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Промежуточный класс при работе с потоками
23 сообщений из 23, страница 1 из 1
Промежуточный класс при работе с потоками
    #40064186
BorodaOleg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Доброго дня!

Столкнулся со странным поведением класса TThread.
Пишу в менеджер потоков. В процессе, чтобы не добавлять в каждый класс однообразные процедуры и переменные создал промежуточный класс:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
unit utlThread;

interface

uses
  Windows, Classes, StdCtrls, utlThreadView,
  utlSendRecive, utlconst;

type
  CThread = class(TThread)
  public
  protected
    iHandle, iThreadID : LongWord;
    SenderClass : TSenderClass;
    ThreadName : string;
    destructor Destroy; override;
    procedure SendThreadView(_Type: Integer; _Message: String);
  end;

implementation

{ TreahTest }

procedure CThread.SendThreadView(_Type : Integer; _Message : String);
Var
  s   : string;
  ID : Integer;
Begin
  ID := 0;
  s := SenderClass.ToStringBox(_Type, _Message);
  ID := GetCurrentThreadID;
  if ThreadViewHandle >= 0 then
    SenderClass.Send(QL_QWERYBOXEVENT,ThreadViewHandle,ID,s);
End;

destructor CThread.Destroy;
var StrMsg      : string;
begin
  StrMsg := 'Процесс выгружен: ' + ThreadName;
  SendThreadView(ET_RELEASE, StrMsg);
  if Suspended then begin
    TerminateThread(Self.Handle, 0);
  end;
  inherited;
end;

end.



Далее создаю потоки:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
 CThreadPull = class(CThread)
     private
      name       : String;
. . . 
     protected
      procedure Execute; override;
      procedure SendEventBox(_Type : Integer; _Message : String);
      procedure SendThreadView(_Type : Integer; _Message : String);
. . . 
      constructor Create(vmaxThreads,vmaxJobs:Integer;vName:String; MF_Handle : HWND);
      destructor Destroy;override;
    End;



В Create добавляю:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
. . .
  ThreadName := 'CThreadPull';
  iHandle := Handle;
  iThreadID := ThreadID;
  StrMsg := 'Процесс инициирован : ' + ThreadName+
            ' ' + IntToStr(iHandle)+ ' ' + 'ThreadID: '+ IntToStr(iThreadID);
  SendThreadView(ET_RELEASE, StrMsg);



По окончании работы выскакивает сообщение о потерях (на картинке) Почему? До этого было только о потере 1 критической секции. В обычных классах я так делал неоднократно, всё вроде как нормально. Число потоков - где то около 80.
Есть у меня подозрение, что если я все эти переменные возверну в наследники, проблема пропадет...

Заранее благодарен.
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064188
BorodaOleg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Сейчас обратил внимание что в одном классе я создавал procedure SendThreadView поверх предка, этих потоков около 35 - больше всех. В других используется процедура предка. Ну и Uncnow этих тоже где-то настолько меньше.

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
 CThreadPull = class(CThread)
     private
      name       : String;
. . . 
     protected
      procedure Execute; override;
      procedure SendEventBox(_Type : Integer; _Message : String);
      procedure SendThreadView(_Type : Integer; _Message : String);
. . . 
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064194
Barmaley57
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Уничтожение экземпляров где?
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064200
BorodaOleg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Barmaley57,

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
destructor CThreadPull.Destroy;
Begin
  if SenderClass <> Nil then FreeAndNil(SenderClass);
  Suspend;
  ClearListAndFree(pull);
  ClearListAndFree(taskList);      
  if box <> nil then FreeAndNil(box);
  if semaphore <> 0 then CloseHandle(semaphore);
  inherited;
End;
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064209
Fr0sT-Brutal
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
BorodaOleg
Barmaley57,

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
destructor CThreadPull.Destroy;
Begin
  if SenderClass <> Nil then FreeAndNil(SenderClass);
  Suspend;
  ClearListAndFree(pull);
  ClearListAndFree(taskList);      
  if box <> nil then FreeAndNil(box);
  if semaphore <> 0 then CloseHandle(semaphore);
  inherited;
End;


Проверки не нужны. И кстати, ты в курсе, что у TThread есть и хэндл, и ИД?
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064237
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BorodaOleg
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
destructor CThread.Destroy;
var StrMsg      : string;
begin
  StrMsg := 'Процесс выгружен: ' + ThreadName;
  SendThreadView(ET_RELEASE, StrMsg);
  if Suspended then begin
    TerminateThread(Self.Handle, 0);
  end;
  inherited;
end;

Зачем? Вы видели код TThread?
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
destructor TThread.Destroy;
begin
  if (FThreadID <> 0) and not FFinished and not FExternalThread then
  begin
    Terminate;
    if FCreateSuspended or FSuspended then
      Resume;
{$IFDEF MSWINDOWS}
    while not FStarted do
{$ELSE}
    while not ((not FCreateSuspended or FInitialSuspendDone) and FStarted) do
{$ENDIF}
      Yield;
    WaitFor;
  end;

Ну и вызвать TerminateThread - это как использовать гильотину вместо цитрамона
BorodaOleg
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
destructor CThreadPull.Destroy;
Begin
  if SenderClass <> Nil then FreeAndNil(SenderClass);
  Suspend;
  ClearListAndFree(pull);
  ClearListAndFree(taskList);      
  if box <> nil then FreeAndNil(box);
  if semaphore <> 0 then CloseHandle(semaphore);
  inherited;
End;

Лихо! Вначале убиваем объект, а потом в родителе к нему обращаемся.

А Suspend вам зачем? Чтобы был повод вызвать TerminateThread и потерять все переменные с управляемым временем жизни?
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064278
YuRock
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BorodaOleg,

А в чём прикол объявлять деструктор в protected?

О том, что Resume, Suspend и особено TerminateThread использовать не нужно никогда - уже сказали.
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064279
YuRock
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
YuRock
А в чём прикол объявлять деструктор в protected?
Удивляюсь, как оно скомпилиться могло.
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064286
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
YuRock
О том, что Resume, Suspend и особено TerminateThread
Resume можно
YuRock
YuRock
А в чём прикол объявлять деструктор в protected?
Удивляюсь, как оно скомпилиться могло.
А в чем проблема? При компиляции был ворнинг. VMT благополучно переписалось. Проблем нет
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064289
YuRock
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_
Resume можно
Разве что, если создавать Suspended. Такое редко нужно, для пулов всяких хитрых, экономящих копейки, и обычно только усложняет всё, сложно смысл этого объяснить. Не пользовался ни разу, если честно. Если я создаю поток - хочу, чтобы он заработал сразу. Если хочу, чтоб он заработал позже - я и создам его позже.

_Vasilisk_
А в чем проблема? При компиляции был ворнинг. VMT благополучно переписалось. Проблем нет

Работать будет, конечно, кроме варнинга проблем не будет. Но варнинг - тоже проблема, если они висят постоянно, тогда программист на все варнинги перестает обращать внимание.
Так чтотлучше б уж компилятор ошибку выдал, я это имел ввиду.
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064349
BorodaOleg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Fr0sT-Brutal

Проверки не нужны. И кстати, ты в курсе, что у TThread есть и хэндл, и ИД?


Проект не мой, и уже натыкался на казусы, когда класс пришибается раньше, а потом еще и в дестрое.
Что есть и хэндл, и ИД? - в курсе. Лог:

Процесс инициализирован : CTaskExequtor:tp Pull8 10756 ThreadID: 844
Процесс инициализирован : CTaskExequtor:tp Pull9 10768 ThreadID: 3728
Процесс инициализирован : CThreadPull 10648 ThreadID: 3952
Процесс инициализирован : CTaskExequtor:abon Hand Pull0 10796 ThreadID: 2504
Процесс инициализирован : CThreadPull 10784 ThreadID: 3424
Процесс инициализирован : CL4Module

Только какая между ними разница - не в курсе
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064357
BorodaOleg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
_Vasilisk_

Зачем? Вы видели код TThread?
Ну и вызвать TerminateThread - это как использовать гильотину вместо цитрамона


Иногда потоки вешались намертво - посоветовали такой способ, вроде помогло.

_Vasilisk_

Лихо! Вначале убиваем объект, а потом в родителе к нему обращаемся.


Тут просто накладка вышла, я уже решил этот промежуточный класс не использовать и прописал SenderClass в потомке.

_Vasilisk_

А Suspend вам зачем? Чтобы был повод вызвать TerminateThread и потерять все переменные с управляемым временем жизни?


Был он тут, я на него как-то и внимания не обращал )
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064373
Fr0sT-Brutal
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
[quot YuRock#22311641]
_Vasilisk_
Resume можно
Разве что, если создавать Suspended. Такое редко нужно, для пулов всяких хитрых, экономящих копейки, и обычно только усложняет всё, сложно смысл этого объяснить. Не пользовался ни разу, если честно. Если я создаю поток - хочу, чтобы он заработал сразу. Если хочу, чтоб он заработал позже - я и создам его позже.
Это нужно, если после создания надо передать потоку всякие дополнительные данные. Чтобы не пихать все в конструктор
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064389
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BorodaOleg
Иногда потоки вешались намертво - посоветовали такой способ, вроде помогло.
Так TerminateProcess сразу используйте. И никаких утечек не будет
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064420
YuRock
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Fr0sT-Brutal
Это нужно, если после создания надо передать потоку всякие дополнительные данные. Чтобы не пихать все в конструктор
Ну вот у меня за всю жизнь такого не было, чтобы не хватило параметров конструктора.
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064422
Фотография makhaon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Fr0sT-Brutal,

авторРазве что, если создавать Suspended. Такое редко нужно, для пулов всяких хитрых, экономящих копейки, и обычно только усложняет всё, сложно смысл этого объяснить
Suspended создавать как раза таки удобно. Я чаще всего Suspended и создаю. Создали, набили поток данными, start, посчиталось/выполнилось, забрали результаты.
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064435
BorodaOleg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
_Vasilisk_
BorodaOleg
Иногда потоки вешались намертво - посоветовали такой способ, вроде помогло.
Так TerminateProcess сразу используйте. И никаких утечек не будет


Нифига не помогает. Если убираю эту строку программа намертво вешается на финише. Если пытаюсь использовать TerminateProcess - вешается мгновенно ))
Если прописываю просто Terminate - висит
Если убиваю Suspend в потомке - висим (
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064438
s62
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
makhaon,

Поток не запустится раньше, чем выполнится весь код в конструкторе (можно посмотреть код конструктора и AfterConstruction класса TThread). То есть вот как Fr0sT-Brutal написал, если данные передаются в конструкторе (а не потом ещё), то Suspend не нужен.
Я раньше этого не знал и писал в конструкторе типа:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
constructor TExchangeThread.CreateWin(aWindow: THandle);
begin
  inherited Create(True);
  FWindow := aWindow;
  FreeOnTerminate := True;
  ...
  Resume;
end;


Можно писать
Код: pascal
1.
2.
3.
4.
5.
6.
7.
constructor TExchangeThread.CreateWin(aWindow: THandle);
begin
  inherited Create(False);
  FWindow := aWindow;
  FreeOnTerminate := True;
  ...
end;
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064439
Fr0sT-Brutal
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
makhaon
Suspended создавать как раза таки удобно. Я чаще всего Suspended и создаю. Создали, набили поток данными, start, посчиталось/выполнилось, забрали результаты.

Это не мне, а Юрку, я как раз так тоже делаю (в предыдущем сообщении цитата съелась)
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064490
YuRock
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Fr0sT-Brutal
в предыдущем сообщении цитата съелась
Кормить надо хорошей кашей, чтоб не съедалась :)
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064497
YuRock
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BorodaOleg
Если пытаюсь использовать TerminateProcess - вешается мгновенно
Не верю :)

BorodaOleg
Если прописываю просто Terminate - висит
Если убиваю Suspend в потомке - висим (

Выход прост - надо прекратить судорожные действия, в выполнить последовательно два шага:

1. Понять, что корректное завершение потока - есть ни что иное, как штатное завершение функции потока (в данном случае - это метод Execute). Завершить работу этой функции можно только двумя путями, и только изнутри неё: 1 - вызвав Exit, 2 - выполнив до самого конца (до самого end;) всю цепочку операторов этой функции. В вашем случае "зависает" потому, что цепочка операторов (это и есть - поток команд) до конца не выполнилась, а продолжает выполняться.

2. После осознания первого пункта, необходимо изменить функцию потока (Execute) таким образом, чтобы она завершалась тогда, когда вы хотите. Влиять на нее (на ее логику) можно, вызывая Terminate (он просто присваивает полю Terminated значение True, больше ничего не делает), но Terminate и так вызывается в деструкторе потока. Если же поток чего-то ждёт (каких-то событий) - то надо сделать так, чтобы перестал ждать (взвести эти события). Если после того, как поток перестал ждать события, он начинает что-то делать - тогда перед этим можно вручную Terminate, чтобы не начинать лишних действий, и сразу выйти.
В общем, логика любая, но результат должен быть один - достижение последнего end процедуры Execute. Никакие TerminateThread и Suspend не помогут, забудь об этих методах навсегда, они только вредны.
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064570
Фотография makhaon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
s62,

Передавать пачку данных в конструктор такое себе удовольствие. Если параметр 1-2, то еще ладно.
...
Рейтинг: 0 / 0
Промежуточный класс при работе с потоками
    #40064618
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
makhaon
Передавать пачку данных в конструктор такое себе удовольствие.
Use record, Luke!
...
Рейтинг: 0 / 0
23 сообщений из 23, страница 1 из 1
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Промежуточный класс при работе с потоками
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]