如何从单独的单元执行线程同步

时间:2013-10-10 13:54:02

标签: multithreading delphi

我有以下问题/问题。

我有一个名为“myGlobalFunctions.pas”的单位。 在这个单元内部,我实现了多个项目使用的多个过程/函数。

项目1使用此单元

项目3使用此单元

项目6使用此单位 等

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

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

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

喜欢“在启动function1之前” ......呼唤 “在function1之后。”

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

但是现在我想在应用程序界面的“function1”更新中实现(使用synchronize)。

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

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

有可能吗?

我该怎么做呢。

可以是线程安全吗?

很多

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

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;

1 个答案:

答案 0 :(得分: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;

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