2013-10-10 4 views
4

У меня есть следующая проблема/вопрос.Как выполнить синхронизацию потока с отдельного блока

У меня есть подразделение с именем myGlobalFunctions.pas. Внутри этого устройства я реализовал несколько процедур/функций, которые используются несколькими проектами.

Проект 1 Использование данного устройства

проект 3 Использование данного устройства

проект 6 Использование данного устройства т.д.

внутри «Проект 1» есть поток, который используют функции внутри «глобальной функции " Ед. изм.

внутри проекта 3 нет нити, но функции используются.

до сих пор эта нить (project1) обеспечивает практически не обновление интерфейса приложения и обновление было сделано до или после вызова функции из «myGlobalFunctions.pas»

как «перед запуском function1» ... вызов «после функции1».

таким образом я могу знать, что делает программа.

Однако теперь я хочу реализовать внутри «функции1» обновление интерфейса приложения (с синхронизацией).

Я хочу отразить в интерфейсе приложения «этап обработки1 ... xx records». (для набора данных есть цикл while).

Использование Synchronize для «project1» и с нормальным ярлыком1.caption = 'message'; application.process для любого другого проекта.

Возможно ли это?

как я могу это сделать.

может быть Thread Safe?

ТКС много

Разван здесь некоторый код, чтобы лучше понять

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

Пожалуйста, [править], чтобы включить ** соответствующие ** части вашего кода, чтобы мы могли попробовать и помочь вам. Ваше описание очень расплывчато, и код поможет сделать его более понятным. (Пожалуйста, напишите * достаточно кода *, чтобы сделать ваш вопрос ясным, пожалуйста, не просто сбрасывайте тонны кода здесь и ожидайте, что мы попытаемся понять его.) Спасибо. –

+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 Я рад, что это было полезно, пожалуйста. –

Смежные вопросы