2013-10-10 171 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我很高興這是有益的,不客氣。 –