2013-10-10 218 views
4

我有以下问题/问题。如何执行线程同步从一个单独的单位

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

项目1对使用本单元

项目3使用这个单元

项目6使用本单元 等

内部“项目1”则存在使用“全局函数内部功能的线程“单位。

项目内部3没有线程但功能被使用。

到目前为止,这个线程(PROJECT1)提供了几乎没有任何应用程序界面的更新和更新过程之前或之后从“myGlobalFunctions.pas”

像调用一个函数做 “开始之前功能1” ...... “在function1之后”调用 。

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

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

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

使用Synchronize for“project1”和正常的label1.caption ='message';任何其他项目的application.process消息。

是否有可能?

我该怎么做这样的事情。

可以线程安全吗?

TKS很多

勒兹万 这里是一些代码,以更好地了解

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

请[edit]包含**代码的相关**部分,以便我们可以尝试和帮助您。你的描述非常含糊,代码会让它更加清晰。 (请发布*只需足够的代码*以使您的问题清晰;请不要在此处转储大量代码,并期望我们尝试解决它。​​)谢谢。 –

+0

如果我理解你是正确的,那么你有一个线程,根据它使用的应用程序,它应该有不同的行为。区别在于与主线程的同步应该执行不同的代码。 –

+0

nope。我想要一个普通的函数对一个线程和一个普通的另一个单元表现不同。 –

回答

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; 

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

+0

tks的信息。事实上,它似乎是一个优雅的方法。我意识到所有......因为我从来没有使用过回调。 –

+0

在学习了什么回调之后..我可以说很好的回答,并且你睁开眼睛。 –

+0

@ PopaOvidiu-Razvan我很高兴这是有益的,不客气。 –