Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 07.06.2015, 18:39   #1
Antony41
Пользователь
 
Аватар для Antony41
 
Регистрация: 20.03.2009
Сообщений: 99
По умолчанию Определить что поток завершен и повторно запустить его

Суть вот в чем при уничтожении потока указатель не устанавливается в nil
соответственно проверка отработал ли поток if not assigned(MyThread) then будет не правильной

подскажите правильно ли я попытался сделать установку указателя в nil
Модуль потока
Код:
unit LicenseThreadUnit;
{
Это основной поток проверки лицензий
}

interface

uses
  System.Classes;

type
  PLicenseThread = ^TLicenseThread;
  TLicenseThread = class(TThread)
  private
    FSelf: PLicenseThread;
  protected
    procedure Execute; override;
  public
    constructor Create(ASelf:PLicenseThread);
    destructor Destroy; override;
  end;

implementation

{ TLicenseThread }

uses MessagesUnit;

constructor TLicenseThread.Create(ASelf:PLicenseThread);
begin
  inherited Create(True);  //Создаем поток остановленным
  FSelf := ASelf;
  FreeOnTerminate := True;
end;

destructor TLicenseThread.Destroy; //Обратите внимание обнуляю указатель на самого себя переданный в конструкторе
begin
  FSelf^ := nil;
  inherited Destroy;
end;

procedure TLicenseThread.Execute;
begin
  {while not Terminated do
    begin
      
    end;}
end;

Код главного потока
Создаю обработчик события OnTerminate
Код:
procedure TConnections.LicenseThreadTerminated(Sender: TObject);
begin
  ShowMessage('Произошло завершение потока.');
end;
Создаю поток так
Код:
procedure TConnections.ThreadsInitialization;
  //Создаем поток контроля лицензии
  LicenseThread := TLicenseThread.Create(@LicenseThread); //Создаем поток он будет остановлен при создании, передаем адрес объекта потока 
  LicenseThread.OnTerminate := LicenseThreadTerminated; //Задаем обработчик
  LicenseThread.Resume; //Запуск потока
end;
Проверку выполняю так
Код:
procedure TConnections.Button1Click(Sender: TObject);
begin
if Assigned(LicenseThread) then
  Showmessage('LicenseThread указатель еще существует!')
else
  Connections.ThreadsInitialization;
end;
Проверил всё работает поток проверка через assigned работает, но можно ли так делать
Antony41 вне форума Ответить с цитированием
Старый 07.06.2015, 21:13   #2
Vapaamies
Ваш К. О.
Участник клуба
 
Аватар для Vapaamies
 
Регистрация: 26.12.2012
Сообщений: 1,774
По умолчанию

Так лучше не делать. Правильней устанавливать в nil указатель на поток в обработчике LicenseThreadTerminated.
Vapaamies вне форума Ответить с цитированием
Старый 07.06.2015, 21:22   #3
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

А для чего нужно тебе проверять поток, если не секрет?
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 07.06.2015, 21:49   #4
Antony41
Пользователь
 
Аватар для Antony41
 
Регистрация: 20.03.2009
Сообщений: 99
По умолчанию

Именно так я и хотел изначально сделать, но предположим я иногда хочу отключать событие
Код:
LicenseThread.OnTerminate := nil
а проверять завершен ли поток необходимость не отпадает
и всё же данный способ имеет место быть? или приведет к AV или еще каким либо нежелательным ситуациям.?

Цитата:
Сообщение от Stilet Посмотреть сообщение
А для чего нужно тебе проверять поток, если не секрет?
данный поток контролирует работу других потоков проверки лицензии и если какой то из потоков вдруг подох при ошибке или же его убили намеренно, то данный поток его перезапускает

Код:
while not Termnated do
begin
if not assigned(ThreadFirst) then
перезапускаем
if not assigned(ThreadSecond) then
перезапускаем
if not assigned(ThreadThird) then
перезапускаем
end

Последний раз редактировалось Stilet; 07.06.2015 в 22:22.
Antony41 вне форума Ответить с цитированием
Старый 07.06.2015, 23:48   #5
Vapaamies
Ваш К. О.
Участник клуба
 
Аватар для Vapaamies
 
Регистрация: 26.12.2012
Сообщений: 1,774
По умолчанию

Цитата:
Сообщение от Antony41 Посмотреть сообщение
Именно так я и хотел изначально сделать, но предположим я иногда хочу отключать событие
Отключать событие надо битовым флагом, и не удалением обработчика. В обработчике этот битовый флаг проверять. Обработчики -- это архитектура приложения, флаги -- настройки, конфигурация. Одно дело -- менять архитектуру, другое -- менять настройки.
Vapaamies вне форума Ответить с цитированием
Старый 08.06.2015, 02:27   #6
Antony41
Пользователь
 
Аватар для Antony41
 
Регистрация: 20.03.2009
Сообщений: 99
По умолчанию

Мне кажется в моем случае лучше всё таки отключить событие, код красивее, и удобнее

При завершении потока выполнется OnTerminate в котором происходит
Код:
ShowMessage('Произошло завершение одного из главных потоков программы. Дальнейшая работа программы не возможна!');
ExitProcess(0);
и программа закрывается

Соответственно для корректного намеренного выхода из программы необходимо сначала остановить поток, так как поток зациклен
Код:
while not Terminated do
необходимо выполнить Terminate

Но тут сработает событие OnTerminate (если его не отключить) и покажет сообщение после здохнет хотя я корректно пытаюсь завершить поток без выполнения OnTerminate

Вот что я сделал
в поток добавил свойство
Код:
property CloseProgram : Boolean write SetCloseProgram;
Код:
procedure TLicenseThread.SetCloseProgram(const Value: Boolean);
begin
  if Value then //Если мы выходим из прораммы
    begin
      OnTerminate := nil; //То выполнение события onTerminate необходимо отменить
      Terminate; //и соответственно завершить поток
    end;
end;
при выходе из программы выполняю не Terminate, а CloseProgram, и событие отменится в самом потоке
Antony41 вне форума Ответить с цитированием
Старый 08.06.2015, 02:28   #7
Antony41
Пользователь
 
Аватар для Antony41
 
Регистрация: 20.03.2009
Сообщений: 99
По умолчанию

Вот весь модуль потока
Код:
unit LicenseThreadUnit;
{
Это основной поток проверки лицензий , в нем содержатся основные переменные
к которым происходит обращение из главного потока программы,
Этот поток запускает другие потоки проверки лицензий а так же в бесконечном цикле проверяет,
запущены ли они, если нет то перезапускает
}

interface

uses
  System.Classes;

type
  PLicenseThread = ^TLicenseThread;
  TLicenseThread = class(TThread)
  private
    FSelf: PLicenseThread;
    procedure SetCloseProgram(const Value: Boolean);
  protected
    procedure Execute; override;
  public
    constructor Create(ASelf:PLicenseThread);
    destructor Destroy; override;
  //При намеренном выходе из программы, установить CloseProgram в True и поток завершится без выполнения события onTerminate
  property CloseProgram : Boolean write SetCloseProgram;

  end;

implementation

{ TLicenseThread }

uses MessagesUnit;

constructor TLicenseThread.Create(ASelf:PLicenseThread);
begin
  inherited Create(True);  //Создаем поток остановленным
  FSelf := ASelf;
  FreeOnTerminate := True;
end;

destructor TLicenseThread.Destroy;
begin
  FSelf^ := nil;
  inherited Destroy;
end;

procedure TLicenseThread.Execute;
begin
  while not Terminated do
    begin
      //ShowMyMessage(0, C_MSG_LOGSTATUS, 'сообщение из основного потока проверки лицензии');
    end;


end;

procedure TLicenseThread.SetCloseProgram(const Value: Boolean);
begin
  if Value then //Если мы выходим из прораммы
    begin
      OnTerminate := nil; //То выполнение события onTerminate необходимо отменить
      Terminate; //и соответственно завершить поток
    end;
end;

end.
Antony41 вне форума Ответить с цитированием
Старый 08.06.2015, 02:39   #8
Antony41
Пользователь
 
Аватар для Antony41
 
Регистрация: 20.03.2009
Сообщений: 99
По умолчанию

Всё же можно ли обнулить указатель в Destroy потока?
ведь событие Destroy выполняется в любом случае, при уничтожении потока
Antony41 вне форума Ответить с цитированием
Старый 08.06.2015, 06:32   #9
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Цитата:
ведь событие Destroy выполняется в любом случае, при уничтожении потока
Да, но принадлежит оно все же классу, который ты собрался обнулять.
Не очень ИМХО идея правильная. Мне думается что тебе нужно пересмотреть механизм проверки полностью. И ничего нигде не обнулять из себя.
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 08.06.2015, 14:50   #10
Vapaamies
Ваш К. О.
Участник клуба
 
Аватар для Vapaamies
 
Регистрация: 26.12.2012
Сообщений: 1,774
По умолчанию

Цитата:
Сообщение от Antony41 Посмотреть сообщение
Мне кажется в моем случае лучше всё таки отключить событие, код красивее, и удобнее
Если судить по аватарам, у нас разное понятие о красоте. На красоту кода тоже влияет, видимо.
Vapaamies вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
как запустить поток второй раз Dеlphi Общие вопросы Delphi 11 04.03.2015 16:45
Ввести натуральное число и определить, верно ли, что сумма его цифр равна 10 ---Demon--- Общие вопросы C/C++ 1 27.10.2014 07:34
Поток выполняется или прерван - нельзя запустить повторно boris-blade Общие вопросы .NET 0 02.04.2010 18:16
Что такое мемтест и как его запустить? Ромио Операционные системы общие вопросы 3 14.08.2009 08:54
Как сделать, чтобы программа запускалась один раз, т.е. повторно запустить нельзя??? Kamikadze_666 Безопасность, Шифрование 7 31.07.2007 08:34