Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Создание потока (TThread)  (Прочитано 10600 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Shouldercannon
Постоялец

ru
Offline Offline

« : 15-12-2011 14:36 » 

Данный поток построен верно?
Код:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls, IdBaseComponent, IdComponent,
  IdTCPConnection, IdTCPClient, IdHTTP;

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

  TNewThread = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  NewThread: TNewThread;
begin
  NewThread := TNewThread.Create(True); // Поток создан и остановлен
  NewThread.FreeOnTerminate := True; // Уничтожить поток после завершения работы
  NewThread.Resume; // Запуск потока
  NewThread.OnTerminate := TNewThread_ThreadTerminate;
end;

procedure TNewThread.Execute;
var
  HTTP: TIdHTTP;
  TMS: TMemoryStream;
begin
  HTTP := TIdHTTP.Create(nil);
  TMS := TMemoryStream.Create;
  try
    try
      HTTP.Get('http://img.yandex.net/i/www/logo.png', TMS);
      TMS.SaveToFile('logo.png');
    except
    end;
  finally
    HTTP.Free;
    TMS.Free;
  end;
end;

procedure TForm1.TNewThread_ThreadTerminate(Sender: TObject);
begin
  // Что-то
end;

end.
 
Как можно TNewThread_ThreadTerminate описать в потоке TNewThread = class(TThread), а не отдельно, если это вообще возможно?
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 15-12-2011 15:43 » 

Цитата: Shouldercannon
  NewThread.Resume; // Запуск потока
  NewThread.OnTerminate := TNewThread_ThreadTerminate;
Мне кажется, сначала нужно закончить настройку, а потом будить поток. Особенно если это касается обработчика завершения потока. Быть может по ошибке поток завершится раньше, чем будет установлен обработчик.

Цитата: Shouldercannon
Как можно TNewThread_ThreadTerminate описать в потоке TNewThread = class(TThread), а не отдельно, если это вообще возможно?
Если я правильно понял вопрос, то нужно создать класс-потомок TNewThread и в его конструкторе добавить в качестве обработчика собственный метод. Тогда все экземпляры нового класса будут иметь этот обработчик.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
zubr
Модератор

by
Offline Offline
Пол: Мужской

« Ответ #2 : 15-12-2011 16:43 » 

Я бы сделал так:
Код:
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    procedure TNewThread_ThreadTerminate(Sender: TObject);
  public
    { Public declarations }
  end;

  TNewThread = class(TThread)
  private

  protected
    procedure Execute; override;
  public
    constructor Create(TerminateEvent: TNotifyEvent); overload;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TNewThread }

constructor TNewThread.Create(TerminateEvent: TNotifyEvent);
begin
  inherited Create(False);
  OnTerminate := TerminateEvent;
  FreeOnTerminate := True;
end;

procedure TNewThread.Execute;
var
  HTTP: TIdHTTP;
  TMS: TMemoryStream;
begin
 HTTP := TIdHTTP.Create(nil);
  TMS := TMemoryStream.Create;
  try
    try
      HTTP.Get('http://img.yandex.net/i/www/logo.png', TMS);
      TMS.SaveToFile('logo.png');
    except
    end;
  finally
    HTTP.Free;
    TMS.Free;
  end;
end;

{ TForm1 }

procedure TForm1.TNewThread_ThreadTerminate(Sender: TObject);
begin
  MessageBox(0, 'NewThread Terminated', nil, MB_OK);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  TNewThread.Create(TNewThread_ThreadTerminate);
end;
Цитата
Как можно TNewThread_ThreadTerminate описать в потоке TNewThread = class(TThread), а не отдельно, если это вообще возможно?
А смысл? Если что то надо сделать в самом потоке по его завершению, то для этого можно вставить какой то код или метод в конец метода Execute. Или переопределить метод Destroy и там выполнить нужный код по завершении потока. Имеет смысл иметь обработчик OnTerminate в другом потоке, который должен знать, что поток NewThread завершился.
« Последнее редактирование: 15-12-2011 16:46 от zubr » Записан
Shouldercannon
Постоялец

ru
Offline Offline

« Ответ #3 : 19-12-2011 08:17 » 

От теории к практике. Вот, что получилось сделать. Возможно, допущены ошибки.
Код: (Delphi)
  TNewThread = class(TThread)
  private
        { Private declarations }
        s: string;
        Bool: Boolean;
  protected
        procedure SyncProc;
        procedure Execute; override;
        procedure DoTerminate; override;
  end;

var
  Form1: TForm1;
  a: string;
  DownloadStatus: Boolean;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  NewThread: TNewThread;
begin
  Button1.Enabled := False;

  NewThread := TNewThread.Create(True); // Поток создан и остановлен
  NewThread.FreeOnTerminate := True; // Уничтожить поток после завершения работы
  NewThread.Resume; // Запуск потока
end;

procedure TNewThread.Execute;
var
  HTTP: TIdHTTP;
  MS: TMemoryStream;
begin
  Bool := True; // Статус выполнения операции (успешно)

  HTTP := TIdHTTP.Create(nil);
  MS := TMemoryStream.Create;
  try
        try
          HTTP.Get('http://rvs.ucoz.ru/files/programs/il2sfbc_update.7z', MS);
          MS.SaveToFile('il2sfbc_update.7z');
        except
          on E: Exception do
          begin
                Bool := False; // Статус выполнения операции (накрылось медным тазом)
                s := E.Message;
          end;
        end;
  finally
        HTTP.Free;
        MS.Free;
  end;

  Synchronize(SyncProc); // Синхронизация с основным потоком
end;

procedure TNewThread.SyncProc;
begin
  DownloadStatus := Bool; // Синхронизация Boolean
  a := s; // Синхронизация string
end;

procedure TNewThread.DoTerminate;
begin
  // Что-то... Если нужно до вызова внешнего OnTerminate (если назначен)
  inherited;
  // Что-то... Если нужно после вызова внешнего OnTerminate (если назначен)
  Form1.Button1.Enabled := True;
  if DownloadStatus then MessageBox(0, 'Скачивание прошло успешно', 'Информация', MB_ICONInformation) else MessageBox(0, PChar('Произошла ошибка при скачивании. ' + a), 'Ошибка', MB_ICONError)
end;
Верно?
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 19-12-2011 08:32 » 

Shouldercannon, чтобы тебе кто-то сказал, верно или неверно, он сперва должен знать, что тебе нужно получить в результате.

А так - это просто сферический класс в вакууме.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Shouldercannon
Постоялец

ru
Offline Offline

« Ответ #5 : 19-12-2011 08:54 » 

Shouldercannon, чтобы тебе кто-то сказал, верно или неверно, он сперва должен знать, что тебе нужно получить в результате.

А так - это просто сферический класс в вакууме.
Я скачиваю в потоке файл, а по завершению этой операции вывожу сообщение о проделанной работе. Во время работы потока я задействовал Boolean, который отображает статус проделанной работы и string, который держит текст ошибки. После завершения работы потока я делаю синхронизацию переменных потока с переменными основного потока. Ещё интересует момент с Button1.Enabled := False;/True;, такое обращение к кнопке допустимо в соответсвующих процедурах?
« Последнее редактирование: 19-12-2011 08:56 от Shouldercannon » Записан
zubr
Модератор

by
Offline Offline
Пол: Мужской

« Ответ #6 : 19-12-2011 09:25 » 

1. Все равно делаешь криво:
NewThread := TNewThread.Create(True); // Поток создан и остановлен
NewThread.FreeOnTerminate := True; // Уничтожить поток после завершения работы
NewThread.Resume; // Запуск потока
2. Button1.Enabled := False;/True; надо синхронизировать с GUI-потоком.
Записан
Shouldercannon
Постоялец

ru
Offline Offline

« Ответ #7 : 19-12-2011 10:36 » 

1. Все равно делаешь криво:
NewThread := TNewThread.Create(True); // Поток создан и остановлен
NewThread.FreeOnTerminate := True; // Уничтожить поток после завершения работы
NewThread.Resume; // Запуск потока
2. Button1.Enabled := False;/True; надо синхронизировать с GUI-потоком.
По поводу первого: не понял выписку кода.
По поводу второго: как сделать сихронизацию с GUI-потоком?
Записан
zubr
Модератор

by
Offline Offline
Пол: Мужской

« Ответ #8 : 19-12-2011 11:05 » 

Цитата
По поводу первого: не понял выписку кода.
Инициализацию потока красивее делать в консрукторе потока. Пример я тебе показывал.
Цитата
По поводу второго: как сделать сихронизацию с GUI-потоком?
Использовать метод Synchronize
Записан
Shouldercannon
Постоялец

ru
Offline Offline

« Ответ #9 : 19-12-2011 12:32 » 

Как производить синхронизацию переменных знаю Ответ #3, а вот с кнопками не разу не делал.
Записан
zubr
Модератор

by
Offline Offline
Пол: Мужской

« Ответ #10 : 19-12-2011 13:11 » 

А какая разница? Form1.Button1.Enabled - тоже переменная, только устанавливаемая через свойство.
Записан
Shouldercannon
Постоялец

ru
Offline Offline

« Ответ #11 : 19-12-2011 13:14 » 

Значит вместо
Код:
Button1.Enabled := False;
нужно писать
Код:
Form1.Button1.Enabled := False;
?
Записан
zubr
Модератор

by
Offline Offline
Пол: Мужской

« Ответ #12 : 19-12-2011 13:25 » 

Значит вместо
Код:
Button1.Enabled := False;
нужно писать
Код:
Form1.Button1.Enabled := False;
?
Не понял. А причем здесь синхронизация? Это вопрос по области видимости переменных. Естественно, если ты устанавливаешь свойство Button1.Enabled в методе класса TNewThread, то надо указывать Form1.Button1.Enabled, а иначе все равно компилятор не пропустит.
Записан
Shouldercannon
Постоялец

ru
Offline Offline

« Ответ #13 : 19-12-2011 14:42 » 

Совсем загнался. В Execute и DoTerminate потока обращаемся к свойствам чего-либо через Form1 или через ту форму, где этот поток. А то речь пошла про сихронизацию Button1.Enable и совсем запутался.
Записан
zubr
Модератор

by
Offline Offline
Пол: Мужской

« Ответ #14 : 19-12-2011 17:52 » 

Как все запущено. Судя по всему ты где то скопипастил код без всякого понятия. Надо изучать литературу по Object Pascal по теме ООП: классы, объекты, область видимости. Извини, объяснять элементарные вещи из учебника нет никакого желания. Педагогика - не моя стихия Улыбаюсь
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines