Pertanyaan Bagaimana menjalankan sinkronisasi benang dari unit terpisah


Saya memiliki masalah / pertanyaan berikut.

Saya memiliki unit bernama "myGlobalFunctions.pas". Di dalam unit ini saya telah mengimplementasikan beberapa prosedur / fungsi yang digunakan oleh beberapa proyek.

proyek 1 menggunakan unit ini

proyek 3 menggunakan unit ini

proyek 6 menggunakan unit ini dll

di dalam "proyek 1" ada benang yang menggunakan fungsi di dalam unit "fungsi global".

di dalam proyek 3 tidak ada benang tetapi fungsinya digunakan.

sejauh ini thread ini (project1) menyediakan hampir tidak ada pembaruan antarmuka aplikasi dan pembaruan dibuat SETELAH atau SEBELUM memanggil fungsi dari "myGlobalFunctions.pas"

seperti "sebelum mulai function1" ... panggilan "setelah function1".

dengan cara ini saya bisa tahu apa yang sedang dilakukan program.

Namun sekarang saya ingin mengimplementasikan di dalam pembaruan "function1" dari antarmuka aplikasi (dengan sinkronisasi).

Saya ingin merefleksikan antarmuka aplikasi "memproses langkah1 ... xx catatan". (ada loop sementara di sana untuk dataset).

menggunakan Sinkronisasi untuk "project1" dan dengan label1.caption = = 'pesan' normal; pesan application.process untuk proyek lainnya.

apa itu mungkin?

bagaimana saya bisa melakukan hal seperti itu.

bisa Thread Aman?

tks banyak

Razvan berikut ini beberapa kode untuk dipahami lebih baik

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
2017-10-10 13:54


asal


Jawaban:


Sepertinya Anda ingin fungsi global Anda menjalankan callback. Anda dapat mencoba pendekatan seperti ini:

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.

Menambahkan callback metode sebagai argumen memungkinkan Anda untuk lulus dalam fungsi apa pun yang Anda inginkan untuk menjalankan metode. Sebagai contoh :

  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; 

terapkan sebagai:

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;

Anda belum memberi tahu kami versi Delphi yang Anda gunakan. Jika Anda menggunakan D2009 atau yang lebih baru, Anda dapat menggabungkan dua panggilan di atas menjadi satu menggunakan metode anonim (dan menyingkirkannya FProgress):

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

Di mana dalam formulir Anda, Anda akan melakukan:

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;

Ini dengan baik memisahkan tanggung jawab. Formulir utama mengirimkan metode pembaruan ke utas (metode, dalam hal ini, untuk memperbarui label). Thread bertanggung jawab untuk menyinkronkan panggilan dan fungsi global, oleh karena itu, tidak perlu peduli apakah callback yang dijalankan berasal dari utas utama atau dari utas lainnya. Thread tahu perlu menyinkronkan metode sehingga harus mengambil tanggung jawab itu.


5
2017-10-10 14:42