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

Multithreading 如何从单独的单元执行线程同步,multithreading,delphi,Multithreading,Delphi,我有以下问题 我有一个名为“myGlobalFunctions.pas”的单元。 在本单元中,我实施了多个项目使用的程序/功能 项目1使用本单元 项目3使用本单元 项目6使用本单元 等 在“项目1”中,有一个线程使用“全局函数”单元中的函数 在项目3中没有线程,但使用了函数 到目前为止,这个线程(project1)几乎没有提供应用程序接口的更新,更新是在从“myGlobalFunctions.pas”调用函数之后或之前进行的 如“启动前功能1” ... 召唤 “在功能1之后” 这样我就可以知道程

我有以下问题

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

项目1使用本单元

项目3使用本单元

项目6使用本单元 等

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

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

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

如“启动前功能1” ... 召唤 “在功能1之后”

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

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

我想在应用程序界面“处理步骤1…xx记录”中反映。(数据集有一个while循环)

对“project1”使用同步,并与普通label1.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;

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

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 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;

这很好地划分了责任。主窗体将更新方法传递给线程(在本例中是更新标签的方法)。线程负责同步调用和全局函数,因此不需要关心它正在执行的回调是否来自主线程或任何其他线程。线程知道它需要同步该方法,因此它应该承担相应的责任。

请包含代码的相关部分,以便我们可以尝试帮助您。您的描述非常模糊,代码将有助于使其更加清晰。(请发布足够的代码来澄清您的问题;请不要在这里倾吐大量代码,并期望我们尝试解决它。)谢谢。如果我理解您的意思是正确的,那么您有一个线程,根据它在哪个应用程序中使用,它的行为应该是不同的。区别在于与主线程的同步应该执行不同的code.nope。我希望一个常规函数对一个线程和另一个普通单元的行为有所不同。全局函数不需要知道代码是否在主线程中执行。为开始信号提供一个回调方法,为进度更新提供另一个回调方法。线程代码也应该与GUI的依赖性分离。这也可以通过回调@J…来处理。。。解释.tks以获取信息。事实上,这似乎是一种优雅的做法。我不完全明白。。。。因为我从来没有和callback一起工作过。在了解了什么是callback之后。。我可以说一个很好的答案,你让我睁大了眼睛。
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;