2016-11-18 31 views
-1

我有在OmniThreadLibrary中終止BackgroundWorker的問題。一切正常,但是當我想終止BackgroundWorker時,終止失敗並且BackgroundWorker仍然活着。因此,以批處理方式運行的整個應用程序仍然存在。Delphi OmniThreadLibrary 3.03b:IBackgroundWorker - 終止不起作用

procedure TEntityIndexer.StartReindex; 
    begin 
    if LoadTable then 
    begin  
    // In a ProcessRecords method I schedule WorkItems for background tasks 
     ProcessRecords; 
     while FCounter > 0 do 
      ProcessMessages; 
    // In ProcessMessages I keep the main thread alive 
     ProcessRecordsContinue; 
    // In ProcessRecordsContinue method I process the results of background tasks and OnRequestDone method 
    end 
    else 
     TerminateBackgroundWorker; 
    end; 

    procedure ProcessMessages; 
    var 
    Msg: TMsg; 
    begin 
    while integer(PeekMessage(Msg, 0, 0, 0, PM_REMOVE)) <> 0 do begin 
     TranslateMessage(Msg); 
     DispatchMessage(Msg); 
    end; 
    end; 

    constructor TEntityIndexer.Create; 
    begin 
    ... 
    CreateBackgroundWorker; 
    end; 

    procedure TEntityIndexer.CreateBackgroundWorker; 
    begin 
    FBackgroundWorker := Parallel.BackgroundWorker 
     .NumTasks(INITasksCount) 
     .Initialize(InitializeTask) 
     .Finalize(FinalizeTask) 
     .OnRequestDone(HandleRequestDone) 
     .Execute(ProcessSupportStrings); 
    end; 

    procedure TEntityIndexer.FinalizeTask(const taskState: TOmniValue); 
    var 
    _obj: TObject; 
    begin 
    if not(taskState.IsObject) then 
     Exit; 
    _obj := taskState.AsObject; 
    if _obj is TServerSessionApp then 
     TServerSessionApp(_obj).ParentApplication.Free; 
    CoUninitialize; 
    end; 

    procedure TEntityIndexer.ProcessRecordsContinue; 
    begin 
    if FStack.Count = 0 then 
     Exit; 
    ... 
    FStack.Clear; 
    StartReindex; 
    end; 

    procedure TEntityIndexer.ProcessRecords; 
    ... 
    begin 
    FVTable.First; 
    while not FVTable.Eof do 
    begin 
     ... 
     _omniValue := TOmniValue.CreateNamed(
     [ovIdKey, _id, 
     ovXMLKey, FVTable.FieldByName('mx').AsString, 
     ovGenKey, FVTable.FieldByName('created').AsString 
     ]); 
     FBackgroundWorker.Schedule(FBackgroundWorker.CreateWorkItem(_omniValue)); 
     Inc(FCounter); 
     FVTable.Next; 
    end; 
    end; 

    procedure TEntityIndexer.ProcessSupportStrings(const workItem: IOmniWorkItem); 
    var 
    ... 
    begin 
    if not(workItem.taskState.IsObject) then 
    ... 
    if not workItem.Data.IsArray then 
     raise Exception.Create('Empty parameters!'); 
    ... 
    // make some JSON and XML strings 
    ... 
    try 
     try 
     workItem.Result := TOmniValue.CreateNamed(
      [... ]); 
    ... 
    end; 

    procedure TEntityIndexer.HandleRequestDone(const Sender: IOmniBackgroundWorker; 
    const workItem: IOmniWorkItem); 
    var 
    ... 
    begin 
    Dec(FCounter); 
    if workItem.IsExceptional then 
    begin 
     // Process the exception 
    end 
    else if workItem.Result.IsArray then 
    begin   
     ...   
     FStack.AddToStack(_stackItem); 
    end; 
    end; 

    procedure TEntityIndexer.InitializeTask(var taskState: TOmniValue); 
    begin 
    CoInitialize(nil); 
    taskState.AsObject := CreateAnotherServerSession; 
    end; 

    procedure TEntityIndexer.TerminateBackgroundWorker; 
    begin 
    // Here is s problem - Termination of the BackgroundWorker doesn't work, but finalization 
    // of background tasks is done 
    FBackgroundWorker.Terminate(INFINITE); 
    FBackgroundWorker := nil; 
    end; 

end. 
+2

您的任務中的代碼響應取消令牌的位置在哪裏? –

+0

我打算繼續。我們需要看到後臺工作者正在執行的代碼能夠回答這個問題。請[編輯]您的問題以包含此代碼。 –

+0

我只是一個平行編程和OTL的初學者,我很困惑,所以我嘗試添加與CancelAll行,我忘了刪除它。但是沒有更多的代碼來響應取消令牌。在這本書(與OTL並行編程)中,沒有提到我必須添加特殊代碼來取消任務,當我想在沒有任何條件的情況下全部停止它們時。但是,當我刪除該行問題仍在繼續。 –

回答

0

好的我找到了一個bug。這不是OTL的錯誤。這是由Finalize()方法中對象的錯誤破壞引起的。 taskState參數變量中的對象釋放不夠。 TaskState參數變量也應該被清除。

procedure TEntityIndexer.FinalizeTask(const taskState: TOmniValue); 
var 
    _obj: TObject; 
begin 
    if not(taskState.IsObject) then 
     Exit; 
    _obj := taskState.AsObject; 
    if Assigned(_obj) then 
     _obj.Free; 
    if _obj is TServerSessionApp then 
     TServerSessionApp(_obj).ParentApplication.Free; 
    // release the objects and clear a taskState variable 
    taskState.Clear; 
    CoUninitialize; 
end; 
相關問題