4

我有以下问题/问题。

我有一个名为“myGlobalFunctions.pas”的单元。在这个单元中,我实现了多个项目使用的多个过程/功能。

项目 1 使用本机

项目 3 使用本机

项目 6 使用本机等

在“项目 1”中有一个使用“全局函数”单元内的函数的线程。

在项目 3 中没有线程,但使用了函数。

到目前为止,这个线程(project1)几乎没有提供应用程序接口的更新,并且更新是在从“myGlobalFunctions.pas”调用函数之后或之前进行的

像“开始函数1之前”......调用“函数1之后”。

这样我就可以知道程序在做什么。

但是现在我想在应用程序接口的“function1”更新中实现(同步)。

我想在应用程序界面中体现“处理 step1 ... xx 记录”。(数据集有一个while循环)。

对“project1”使用 Synchronize 并使用普通 label1.caption = 'message'; 任何其他项目的 application.process 消息。

可能吗?

我怎么能做这样的事情。

可以是线程安全的吗?

很多

Razvan 这里有一些代码可以更好地理解

THREAD UNIT

procedure TThreadSyncronizeProcess.SignalStart;
begin
  frmMain.sbMain.Panels[2].Text := 'Syncronizare in desfasurare...'; -- exist all the time
  if Assigned(frmSyncronize) then begin     -- check if exist this
    frmSyncronize.logMain.WriteFeedBackMessage('Pornire syncronizare...', '', EVENTLOG_INFORMATION_TYPE, True);
  end;
end;


procedure TThreadSyncronizeProcess.Execute;
var ..... declarations
begin
  Synchronize(SignalStart); -- this is normal call within thread update interface
  try
    try
      workSession        := TIB_Session.Create(nil);
      workDatabase       := TIB_Database.Create(workSession);
        ... creating more components and setup them ...

      uSyncronizareFunctions.SetupDatabase(workDatabase, workSession, transactionWrite, transactionRead);
      uSyncronizareFunctions.SetupDataSnapConnection(workConnectionRead, providerRead);
      if Assigned(frmSyncronize) then begin
        uSyncronizareFunctions.SetupFeedBack(frmSyncronize.logMain);
      end;

      try
          Synchronize(SignalMessage);
          // this next function is from the "global unit"
          isAllOk := uSyncronizareFunctions.ImportOperatoriAutorizati(workImage, workLabelProgress, True);
          isAllOk := isAllOk and uSyncronizareFunctions.ImportJudete;
          isAllOk := isAllOk and uSyncronizareFunctions.ImportLocalitati;
          isAllOk := isAllOk and uSyncronizareFunctions.ImportUM;
          isAllOk := isAllOk and uSyncronizareFunctions.ImportFurnizori;
          isAllOk := isAllOk and uSyncronizareFunctions.ImportClasificari;
      except
        on e : Exception do begin
          raise Exception.Create(dmMain.GetDataSnapExceptionMessage(e.Message));
        end;
      end;
    except
      on e : Exception do begin
        baseMessage := e.Message;
        Synchronize(SignalMessage);
      end;
    end;
  finally
    workDatabase.ForceDisconnect;
    FreeAndNil(transactionRead);
        ... etc
  end;
  Synchronize(SignalFinish);
end;



global function unit
unit uSyncronizareFunctions;

function  ImportOperatoriAutorizati(imgDone : TImage; labelProgress : TLabel; isThread : Boolean) : Boolean;
var workQuery  : TIB_Query;
    serverData : TClientDataSet;
begin
  Result := True;
  try
    ... create all that we need

    serverData.Close;
    serverData.CommandText := 'SELECT * FROM OPERATORI_AUTORIZATI WHERE REC_VERSION > :ARECVERSION ORDER BY REC_VERSION, ID';
    serverData.Params.Clear;
    serverData.Params.CreateParam(ftInteger, 'ARECVERSION', ptInput);
    serverData.Params.ParamByName('ARECVERSION').AsInteger := lastVersion;
    serverData.Active := True;

        ...... I want here to signal start

    while not serverData.Eof do begin
      try
        globalInsert_Tran.StartTransaction;

        workQuery.Close;
        workQuery.ParamByName('AIDGLOBAL').AsString := serverData.FieldByName('IDGLOBAL').AsString;
        workQuery.Open;
        if workQuery.IsEmpty then begin
          workQuery.Insert;
          workQuery.FieldByName('IDGLOBAL').AsString   := serverData.FieldByName('IDGLOBAL').AsString;
        end else begin
          workQuery.Edit;
        end;
        workQuery.FieldByName('NUME').AsString           := serverData.FieldByName('NUME').AsString;
        workQuery.FieldByName('COD_AUTORIZARE').AsString := serverData.FieldByName('COD_AUTORIZARE').AsString;
        workQuery.FieldByName('OTHER_INFO').AsString     := serverData.FieldByName('OTHER_INFO').AsString;
        workQuery.FieldByName('DATASTERGERE').AsVariant  := GetValueDate(serverData.FieldByName('DATASTERGERE').AsDateTime);
        workQuery.FieldByName('REC_VERSION').AsInteger   := serverData.FieldByName('REC_VERSION').AsInteger;
        workQuery.Post;

        MarkRecordAsDirtyFalse(workQuery);
        globalInsert_Tran.Commit;

        ...... I want here to signal progress and to see in the application interface "processing record xx/100" or any other message


      except
        on e : Exception do begin
          Result := False;
          globalInsert_Tran.Rollback;
        end;
      end;

      serverData.Next;
    end;
  finally
    FreeAndNil(serverData);
    FreeAndNil(workQuery);
  end;
end;
4

1 回答 1

5

看起来您希望您的全局函数执行回调。您可以尝试这样的方法:

unit MyGlobalMethods;    

interface
  uses
    System.SysUtils;
  type
    // define a method signature for your callback
    TSomeCallback = procedure(progress : integer) of object;

  // add a callback argument to your function (initializing to nil will make
  // the parameter optional and will not break your previous implementations)
  function GlobalFunction(arg1 : integer; 
                          AMethodCallback : TSomeCallback = nil) : boolean;

implementation

function GlobalFunction(arg1 : integer; 
                        AMethodCallback : TSomeCallback) : boolean;
var i : integer;
begin
  for i := 0 to arg1 do begin
    sleep(10);  // Do some work
    // report progress by executing the callback method
    // only do this if a method has been passed as argument
    if (i mod 100 = 0) and (Assigned(AMethodCallback)) then AMethodCallback(i);
  end;
  result := true;
end;

end.

添加方法回调作为参数允许您传入任何您希望执行该方法的函数。例如 :

  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    procedure UpdateProgress(progress : integer);
  end;

  TSomeThread = class(TThread)
    private
      FProgressCallback : TSomeCallback;
      FProgress : integer;
      procedure SynchronizeCallback(progress : integer);
      procedure DoCallback;
    public
      procedure Execute; override;
      property OnFunctionProgress : TSomeCallback 
                               read FProgressCallback write FProgressCallback;
  end; 

实现为:

procedure TSomeThread.Execute;
begin
  GlobalFunction(1000, SynchronizeCallback);
end;

procedure TSomeThread.SynchronizeCallback(progress: Integer);
begin
  FProgress := progress;
  Synchronize(DoCallback);
end;

procedure TSomeThread.DoCallback;
begin
  if Assigned(FProgressCallback) then FProgressCallback(FProgress);
end;

您还没有告诉我们您使用的是什么版本的 Delphi。如果您使用的是 D2009 或更新版本,您可以使用匿名方法将上述两个调用捆绑为一个(并摆脱FProgress):

procedure TSomeThread.SynchronizeCallback(progress: Integer);
begin
  Synchronize(procedure
              begin
                if Assigned(FProgressCallback) then FProgressCallback(progress);
              end;);
end;

在你的表格中你会做什么:

procedure TForm1.UpdateProgress(progress: Integer);
begin
  label1.Caption := IntToStr(progress);
end;

procedure TForm1.Button1Click(Sender: TObject);
var someThread : TSomeThread;
begin
  someThread := TSomeThread.Create(true);
  someThread.FreeOnTerminate := true;
  someThread.OnFunctionProgress := UpdateProgress;
  someThread.Start;
end;

这很好地分离了职责。主窗体将更新方法传递给线程(在这种情况下,更新标签的方法)。线程负责同步调用和全局函数,因此,不需要关心它正在执行的回调是来自主线程还是来自任何其他线程。线程知道它需要同步方法,所以它应该承担这个责任。

于 2013-10-10T14:42:18.243 回答