Создать событие и поделиться переменными - PullRequest
1 голос
/ 08 ноября 2011

Я использую Delphi 2007 и потоки.

Моя проблема (извините, я постараюсь объяснить лучше):

1) Я создал файл "utilities.pas", где у меня есть функция, которую я использую больше. 2) Я создал новую программу, в этой программе у меня есть один поток 3) в методе выполнения потока я вызываю одну функцию в моем файле "utilities.pas". Эта функция подключается к FTP с использованием умных компонентов (tclftp). Эти компоненты регистрируют ответ сервера в выделенном событии. То, что я хотел бы сделать, это сохранить журнал в списке строк и затем отправить список строк обратно в вызывающий поток.

Это часть файла "utilities.pas":

// I created TEventHandlers because it's the only way to assign the event runtime
// without having a class
type
 TEventHandlers = class
  procedure clFtp1SendCommand(Sender: TObject; const AText: string);
 end;

var EvHandler: TEventHandlers; 

// this is the porcedure called from the thread. i want to send the stringlist
// back to it containing the ftp log
procedure Test(VAR slMain: tStringlist);
var cFTP: TclFtp;
begin
 cFTP := TclFtp.Create(nil);

 cFTP.Server := 'XXX';
 cFTP.UserName := 'XXX';
 cFTP.Password := 'XXX';
 cFTP.OnSendCommand := EvHandler.clFtp1SendCommand;

 // i connect to the ftp
 cFTP.Open;

 FreeAndNil(cFTP);
end;

procedure TEventHandlers.clFtp1SendCommand(Sender: TObject; const AText: string);
begin
 // here the component (cftp) sends me back the answer from the server.
 // i am logging it

 // HERE IT'S THE PROBLEM:
 // I can't reach slMain from here.....

 slmain.add(Atext);
end;

это вызывающая нить:

procedure TCalcThread.Execute;
var slMain: tstringlist;
begin
  inherited;

  slmain := tstringlist.create(nil);

  Test(slmain);

  if slMain.count > 0 then
    slMain.savetofile('c:\a.txt');

  // i won't free the list box now, but in the thread terminated.
end;

это основная программа:

procedure TfMain.ThreadTerminated(Sender: TObject);
Var ExThread: TCalcThread;
begin
  ExThread := (Sender as TCalcThread);

  if ExThread.slMain.Count > 0 then
    ExThread.slMain.SaveToFile('LOG\Errori.log');

 freeandnil(slMain);
end;

Пожалуйста, кто-нибудь может мне помочь в решении этого? Я действительно не знаю, что делать. Я надеюсь, теперь это более ясно.

p.s. спасибо за весь ответ ..

Ответы [ 3 ]

0 голосов
/ 08 ноября 2011

Другой подход заключается в том, чтобы ваш объект потока имел свой собственный экземпляр списка строк и свой собственный cFTP.Если вам нужен один «главный поток», в который все записывает (возможно, для краткого изложения того, что каждый поток выполнил), используйте этот класс: TThreadStringList от Tilo Eckert http://www.swissdelphicenter.ch/torry/showcode.php?id=2167

0 голосов
/ 08 ноября 2011

Перехватывает событие в классе потока и запускает собственное типизированное событие из этого обработчика.Синхронизируйте этот звонок!И попробуйте предотвратить глобальную переменную.Все это так:

type
  TFtpSendCommandEvent = procedure(Mail: TStrings; const AText: String) of object;

  TMyThread = class(TThread)
  private
    FclFtp: TclFtp;
    FslMail: TStrings;
    FOnFtpSendCommand: TFtpSendCommandEvent;
    FText: String;
    procedure clFtpSendCommand(Sender: TObject; const AText: String);
    procedure DoFtpSendCommand;
  protected
    procedure Execute; override;
  public
    // You could add this property as parameter to the constructor to prevent the
    // need to assign it separately
    property OnFtpSendCommand: TFtpSendCommandEvent read FOnFtpSendCommand
      write FOnFtpSendCommand;
  end;

// If you dont want to make this a property or private field of the thread class:
var
  EvHandler: TFtpSendCommandEvent;

{ TMyThread }

procedure TMyThread.clFtpSendCommand(Sender: TObject; const AText: string);
begin
  // Store the AText parameter temporarily in a private field: Synchronize only 
  // takes a parameterless method
  FText := AText;
  Synchronize(DoFtpSendCommand);
end;

procedure TMyThread.DoFtpSendCommand;
begin
  if Assigned(FOnFtpSendCommand) then
    FOnFtpSendCommand(FslMail, FText);
  // Or, if you really like to use that global variable:
  if Assigned(EvHandler) then
    EvHandler(FslMail, FText);
end;

procedure TMyThread.Execute;
begin
  ...
  FclFtp := TclFtp.Create(nil);
  FslMail := TStringList.Create(nil);
  try
    FclFtp.Server := 'XXX';
    FclFtp.UserName := 'XXX';
    FclFtp.Password := 'XXX';
    FclFtp.OnSendCommand := clFtpSendCommand;
    FclFtp.Open;
  finally
    FreeAndNil(FclFtp);
    FreeAndNil(FslMail);
  end;
  ...
end;
0 голосов
/ 08 ноября 2011

Я думаю, что одним (BAD) подходом было бы создание пула компонентов в основном потоке или во время разработки и назначение одного для каждого потока.то есть 5 экземпляров cFTP, 5 строковых списков, 5 потоков.

Обновление: Мартин Джеймс указывает, почему это ужасная идея, и я согласен.Так что не делай этого.Почта остается сдерживающим фактором.

...