Jump to content

Primož Gabrijelčič

Members
  • Content Count

    246
  • Joined

  • Last visited

  • Days Won

    11

Posts posted by Primož Gabrijelčič


  1. For a timer, call Task.SetTimer and timer event will be called automatically. 

     

    Something like this:

    uses
      OtlTaskControl;
    
    type
      TWorker = class(TOmniWorker)
      protected
        function  Initialize: boolean; override;
      public
        procedure TimerCallback;
      end;
    
    function TWorker.Initialize: boolean;
    begin
      Result := inherited Initialize;
      if Result then
        Task.SetTimer(1, 100, TimerCallback);
    end;
    
    procedure TWorker.TimerCallback;
    begin
      // called every 100 ms
    end;
    
    var
      task: IOmniTaskControl;
    
    task := CreateTask(TWorker.Create()).Run;

     


  2. This is actually a COM problem, I believe, and I know almost nothing about COM, so please consider that my thinking may be entirely wrong.

     

    believe that you are having problems because you initialize your server in tmApartment mode but then access it from multiple threads. http://docwiki.embarcadero.com/RADStudio/Sydney/en/Choosing_a_Threading_Model says for tmApartment: " All client calls use the thread in which the object was created." And the object is created in the main thread.

     

    Does your code work if you use TThread instead of OTL to run async tasks?


  3. If Synchronize is not working (can't tell why without your code), use Queue with a record containing (data, result, flag) and wait for main thread to set the flag. Like this:

    var
      res, data: ...
      flag: boolean;
    
    flag := false;
    
    TThread.Queue(nil,
      procedure
      begin
        res := Process(data);
        flag := true;
      end);
    
    while not flag do Sleep(0);

    Or make 'flag' an event and wait on it. 


  4. SimplePipeline is, well, simple. This is the TButton event handler:

    procedure TfrmSimplePipeline.btnPipelineClick(Sender: TObject);
    var
      pipeline: IOmniPipeline;
      i: Integer;
      v: TOmniValue;
    begin
      pipeline := Parallel.Pipeline;
      pipeline.Stage(AddOne);
      pipeline.Stage(Invert);
      pipeline.Run;
    
      for i := 1 to 5 do
        pipeline.Input.Add(i);
      pipeline.Input.CompleteAdding;
    
      for v in pipeline.Output do
        lbLog.Items.Add(Format('%.3f', [v.AsDouble]));
    
      pipeline := nil;
    end;

    As you can see, the code starts the pipeline and then runs the loop that processes the results. This loop is run in a main thread and therefore blocks the UI. If you slow down the pipeline, it needs more time to generate the results and UI is blocked.


  5. No, WaitFor is not the right choice.

     

    Just use TThread.Queue and execute the code in the main thread. Something like:

     

    res := CalculateTheResult();
    TThread.Queue(nil,
      procedure
      begin
        // This procedure will execute in the main thread.
        // The address of the 'res' variable will be automatically captured so you can use its value here.
        ProcessInMainThread(res);
      end);

     


  6. DSiWaitForTwoObjects is just a shortcut which calls WaitForMultipleObjects Windows API with two handles. In this case it will return with status WAIT_TIMEOUT when a timeout elapses, WAIT_OBJECT_1 when task.Comm.NewMessageEvent is signalled or WAIT_OBJECT_0 when task.TerminateEvent is signalled.


  7. Parallel.For by default works in "blocking" mode. IOW, while the Parallel.For is being executed, owner thread (main thread in your case) does nothing else. Most importantly - it does not process messsages.

     

    There are two ways around this problem.

    1.  Use the .NoWait qualifier: FFor := Parallel.For(...).TaskConfig(...).NumTasks(...).NoWait.Execute(...). (http://www.omnithreadlibrary.com/book/chap06.html#highlevel-for, section 3.11.1) Read here why you have to store the result of the Parallel.For call into a field: http://www.omnithreadlibrary.com/book/chap06.html#leanpub-auto-a-life-cycle-of-an-abstraction.
    2. Execute the Parallel.For asynchronously via Parallel.Async mechanism (http://www.omnithreadlibrary.com/book/chap06.html#highlevel-async):
      Parallel.Async(
        procedure begin
          Parallel.For....Execute();
        end);

       

     


  8. If the OnTerminated is not called, then the task owner (MainTask) is not processing messages. If MainTask is an OTL task, then you can just call it's function MsgWait when you create it.

    MainTask := CreateTask(TOmniWorkerDescendant.Create()).MsgWait;

     

    • Thanks 1

  9. 4 minutes ago, Sonjli said:

    any idea for the OnTerminated event in the child task?

    Missed that one, sorry.

     

    If a OnTerminated is not called (but is called when the task does not die), then the task is probably killed with TerminateThread somewhere.


  10. If you run your program in debugger, it should pop up when the exception occurs - unless you have that exception type listed on the 'ignored exception' list.

     

    Alternatively, open OtlTaskControl unit and search for TOmniTask.InternalExecute. Inside you'll find:

            try
              if otSharedInfo_ref.ProcessorGroup >= 0 then
                otExecutor_ref.SetProcessorGroup(otSharedInfo_ref.ProcessorGroup);
              if otSharedInfo_ref.NUMANode >= 0 then
                otExecutor_ref.SetNUMANode(otSharedInfo_ref.NUMANode);
              otExecutor_ref.Asy_Execute(Self);
            except
              on E: Exception do begin
                taskException := Exception(AcquireExceptionObject);
                FilterException(taskException);
                if assigned(taskException) then
                  SetException(taskException);
              end;
            end;

    This is the main exception handler for a task. You can log information inside the exception handler or put a breakpoint there.

    • Thanks 1

  11. OmniThreadLibrary 3.07.8 has just been released. It contains few small fixes + support for Delphi 10.4 Sydney.

     

    Changelog:

     

    • New features:
      • Implemented IOmniTask.RegisterWaitObject with an anonymous method callback.
      • [Jacek Laskowski] donated a new OTL icon (res\OTL.ico).
      • Added Delphi 10.4 Syndey packages.
    • Bug fixes:
      • [sglienke] A reference to an anonymous method executor in IOmniTask is cleaned up as soon as possible. This allows OTL tasks to be executed from a package. [issue #132]
      • TOmniMREW.TryEnterReadLock and .TryEnterWriteLock were returning True on timeout.
      • SetOnMessage(nil) works correctly.
      • Fixed invalid FreeAndNil of an interface in TOmniFuture<T>.Execute.
      • Compiles with Delphi 10.4 Sydney.

     

    https://github.com/gabr42/OmniThreadLibrary/releases/tag/release-3.07.8

    • Like 5
    • Thanks 1
×