Jump to content

Primož Gabrijelčič

Members
  • Content Count

    247
  • Joined

  • Last visited

  • Days Won

    11

Everything posted by Primož Gabrijelčič

  1. Primož Gabrijelčič

    DSIWin32 ComObj

    That's an implementation bug in DSiWin32. I'll fix that, thanks for the report. DSiWin32 should work correctly in Win64. If not, that's a bug. (Yeah, indeed, naming ...)
  2. Primož Gabrijelčič

    Messageloop in Omnithread task

    By default, an OTL task does not process windows messages (which is requirement for TTimer to work). To enfore windows message processing, call the MsgWait method of your task controller interface before running/scheduling the task. Like this: task := CreateTask(TWorker.Create()).MsgWait.Run; Read more here: http://www.omnithreadlibrary.com/book/chap07.html#lowlevel-tomniworker-msgwait
  3. Primož Gabrijelčič

    Messageloop in Omnithread task

    Variant 1: Use a 'procedure' worker (`procedure Worker(const task: IOmniTask)'). Then you can implement your message loop inside. Variant 2: Use a `TOmniWorker` descendant (as in my example). It will implement its own message loop. Variant 2a: Override parts of the TOmniWorker message loop (but I actually don't remember anymore how that is done 😠 ). You can handle most stuff with Variant 2. In addition to timers you can call Task.RegisterWaitObject to connect code to any waitable handle. See demo 31_WaitableObjects for more information. Read more here: http://www.omnithreadlibrary.com/book/chap07.html#lowlevel-iomnitask-registerwaitobject.
  4. Primož Gabrijelčič

    Messageloop in Omnithread task

    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;
  5. Primož Gabrijelčič

    [Q] OmniThreadLibry AV at Task.Invoke

    Please provide a minimal program that demonstrates the problem.
  6. Primož Gabrijelčič

    10.4.1 Released today

    Long, long time ago 🙂 A quick google search found out that it was introduced in Delphi 4: http://www.blong.com/Conferences/DCon99/VCLSourcery/VCLSourcery.htm. Kudos to @blong who keeps 20 year old posts alive on the web!
  7. Primož Gabrijelčič

    10.4.1 Released today

    And on other systems it's just a wrapper around pthread_rwlock.
  8. Primož Gabrijelčič

    Omnithread DELPHI, many calls in the same function

    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. I 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?
  9. Primož Gabrijelčič

    Omnithread DELPHI, many calls in the same function

    I'm very sorry but I really don't speak any Frech. Can you please translate your question?
  10. Primož Gabrijelčič

    Sample for TWaitFor (or something similar)

    For Synchronize mechanism to work, console application should be calling function CheckSynchronize from System.Classes repeatedly. You can do that from the message processing loop.
  11. Primož Gabrijelčič

    Sample for TWaitFor (or something similar)

    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.
  12. Primož Gabrijelčič

    Understanding UniqueFilter stage from WebSpider demo

    Indeed. IOmniBlockingCollection implements an enumerator which waits for the next available value. The only way to terminate such for loop is to call input.CompleteAdding which signals the enumerator that no new values can ever be produced.
  13. Primož Gabrijelčič

    Adding call to sleep blocks stage in pipeline

    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.
  14. Primož Gabrijelčič

    Understanding UniqueFilter stage from WebSpider demo

    UniqueFilter does not go out of scope. If defined in this format (with input, output: IOmniBlockingCollection parameters), pipeline only calls it once. The 'for url in input' loop is the one that processes all elements that arrive via the input pipeline.
  15. Primož Gabrijelčič

    Sample for TWaitFor (or something similar)

    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);
  16. Primož Gabrijelčič

    Stopping a TimedTask

    Can I get a minimal reproducible example project, please?
  17. Primož Gabrijelčič

    DSiWaitForTwoObjects

    Sorry, impossible to guess 😞 Would need a test app that shows that behaviour to say more.
  18. Primož Gabrijelčič

    DSiWaitForTwoObjects

    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.
  19. Primož Gabrijelčič

    Parallel.For and Timer

    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. 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. 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);
  20. Primož Gabrijelčič

    Task dies unexpectedly

    Your way of killing children is fine. It should not cause the behaviour you are observing.
  21. Primož Gabrijelčič

    Task dies unexpectedly

    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;
  22. Primož Gabrijelčič

    Task dies unexpectedly

    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.
  23. Primož Gabrijelčič

    Task dies unexpectedly

    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.
  24. Primož Gabrijelčič

    Doubt about anonymous method

    I see no obvious reasons why this could cause problems. IOW, I think it should work, yes.
  25. Primož Gabrijelčič

    Revisiting TThreadedQueue and TMonitor

    Please go fight in private and stop killing this great thread.
×