-
Content Count
247 -
Joined
-
Last visited
-
Days Won
11
Everything posted by Primož Gabrijelčič
-
Object destroyed too soon?
Primož Gabrijelčič replied to Primož Gabrijelčič's topic in RTL and Delphi Object Pascal
Yes, it is definitely not a fast solution. It is elegant for the user, though. -
Object destroyed too soon?
Primož Gabrijelčič replied to Primož Gabrijelčič's topic in RTL and Delphi Object Pascal
This works, but requires lots of code if I would want to implement it with the original (very rich) `TOmniValue` record: IOmniValueFwd = interface; TOmniValue = record private FOwnedObject: IAutoDestroyObject; function GetAsOwnedObject: TObject; procedure SetAsOwnedObject(const Value: TObject); public class operator Implicit(const ov: TOmniValue): IOmniValueFwd; property AsOwnedObject: TObject read GetAsOwnedObject write SetAsOwnedObject; end; IOmniValueFwd = interface ['{4CCE0702-1CBF-4467-8185-8C38C37BA624}'] function GetAsOwnedObject: TObject; function GetValue: TOmniValue; procedure SetAsOwnedObject(const Value: TObject); property AsOwnedObject: TObject read GetAsOwnedObject write SetAsOwnedObject; property Value: TOmniValue read GetValue; end; TOmniValueFwd = class(TInterfacedObject, IOmniValueFwd) strict private FOmniValue: TOmniValue; strict protected function GetAsOwnedObject: TObject; function GetValue: TOmniValue; procedure SetAsOwnedObject(const Value: TObject); public constructor Create(const ov: TOmniValue); property AsOwnedObject: TObject read GetAsOwnedObject write SetAsOwnedObject; property Value: TOmniValue read GetValue; end; IWorkItem = interface ['{7C583FC8-90DD-46A5-81B9-81B911AA1CBE}'] function GetResult: IOmniValueFwd; procedure SetResult(const Value: IOmniValueFwd); property Result: IOmniValueFwd read GetResult write SetResult; end; I can then use: procedure Test(const workItem: IWorkItem); begin workItem.Result.AsOwnedObject := TTestObj.Create; end; or: procedure Test(const workItem: IWorkItem); var ov: TOmniValue; begin ov.AsOwnedObject := TTestObj.Create; workItem.Result := ov; end; And both work fine. full code here -
Object destroyed too soon?
Primož Gabrijelčič replied to Primož Gabrijelčič's topic in RTL and Delphi Object Pascal
I'm thinking about changing `IWorkItem.Result` into `TOmniValueClass = class ...` where `TOmniValueClass` exports same API as `TOmniValue` and forwards all requests to a private `TOmniValue` record. LTR: Meh, doesn't work. That makes the getter work fine, but again stops the setter from working 😞 -
Object destroyed too soon?
Primož Gabrijelčič replied to Primož Gabrijelčič's topic in RTL and Delphi Object Pascal
Hmmm, I'll have to think about it. That can be a solution but I'm afraid I will cause too big mess. Thanks. -
High-level abstractions - Difficulties in choosing and using appropriate strategies for solving my task.
Primož Gabrijelčič replied to Shrinavat's topic in OmniThreadLibrary
You have: Renderer := Parallel.ParallelTask.NumTasks(numTasks).NoWait .Execute( procedure begin workItem := RenderQueue.Next; ... end); and then: for iTask := 0 to numTasks-1 do begin TileSource := workItem.Data['TileSource' + iTask.ToString]; RenderQueue.Add(TOmniValue.Create([iTask, TileSource])); end; If you change only the parameter to `ParallelTask.NumTasks`, some tasks won't ever get data because you'll schedule only `numTasks` items to `RenderQueue`. -
Object destroyed too soon?
Primož Gabrijelčič replied to Primož Gabrijelčič's topic in RTL and Delphi Object Pascal
Do we have any neat solution for that problem? I can change `IWorkItem` to: IWorkItem = interface ['{7C583FC8-90DD-46A5-81B9-81B911AA1CBE}'] function GetResult: POmniValue; procedure SetResult(const Value: TOmniValue); property Result: POmniValue read GetResult; end; This allows me to use: workItem.Result.AsOwnedObject := TTestObj.Create; But it also prevents me from doing: workItem.Result := TTestObj.Create; Which is more common usage. Grrrrr! -
High-level abstractions - Difficulties in choosing and using appropriate strategies for solving my task.
Primož Gabrijelčič replied to Shrinavat's topic in OmniThreadLibrary
`workItem.Result` is a record property. Because of that, this code: workItem.Result.AsOwnedObject := TBitmap32.Create(256,256); is equivalent to running: var tmp: TOmniValue; tmp := workItem.Result; tmp.AsOwnedObject := TBitmap32.Create(256,256); And that fails. You should change the code to: var tmp: TOmniValue; tmp.AsOwnedObject := TBitmap32.Create(256,256); workItem.Result := tmp; I'll see if I can change the implementation of `IOmniWorkitem` to prevent such problems. -
Object destroyed too soon?
Primož Gabrijelčič replied to Primož Gabrijelčič's topic in RTL and Delphi Object Pascal
Doh! I knew I was just stupid. To recap (for people who don't want to dig through ton of code). procedure Test(const workItem: IWorkItem); begin workItem.Result.AsOwnedObject := TTestObj.Create; end; is equivalent to: procedure Test(const workItem: IWorkItem); var tmp: TOmniValue; begin tmp := workItem.Result; tmp.AsOwnedObject := TTestObj.Create; end; To do it correctly, one must change the code to: procedure Test(const workItem: IWorkItem); var ov: TOmniValue; begin ov.AsOwnedObject := TTestObj.Create; workItem.Result := ov; end; Thank you, guys! -
High-level abstractions - Difficulties in choosing and using appropriate strategies for solving my task.
Primož Gabrijelčič replied to Shrinavat's topic in OmniThreadLibrary
Minimized problem: Maybe somebody can tell me what is going on because I'm clueless. -
High-level abstractions - Difficulties in choosing and using appropriate strategies for solving my task.
Primož Gabrijelčič replied to Shrinavat's topic in OmniThreadLibrary
Indeed, if you set `workItem.Result` as owned object, it gets destroyed immediately after the `Asy_Execute` exits. This is the minimal code that reproduces the problem: procedure TfrmBackgroundWorkerImageFactory.Asy_Factory(const workItem: IOmniWorkItem); begin if not workItem.CancellationToken.IsSignalled then workItem.Result.AsOwnedObject := TBitmap32.Create(256,256); end; At the moment, don't use `OwnsObject` or `AsOwnedObject` at that point. I'll dig in to see what's going on. -
High-level abstractions - Difficulties in choosing and using appropriate strategies for solving my task.
Primož Gabrijelčič replied to Shrinavat's topic in OmniThreadLibrary
TNX. I have to update, obviously 🙂 -
Create a reproducible test case and post i here. BTW, why are you createing 4000 tasks? Surely, there's a better way to solve your problem.
-
High-level abstractions - Difficulties in choosing and using appropriate strategies for solving my task.
Primož Gabrijelčič replied to Shrinavat's topic in OmniThreadLibrary
I see accvio in G32.pas in procedure TCustomBitmap32.ChangeSize(var Width, Height: Integer; NewWidth, NewHeight: Integer); begin FBackend.ChangeSize(Width, Height, NewWidth, NewHeight); end; FBackend is nil Sorry, no idea why. -
Caching with class variables
Primož Gabrijelčič replied to Primož Gabrijelčič's topic in Tips / Blogs / Tutorials / Videos
Don't think so as we don't use crazily big sets. Plus this code is mostly used for compatibility reason; because some old configuration files store enum and set data as integers. But of course, all code that can fail, will fail. -
Caching with class variables
Primož Gabrijelčič replied to Primož Gabrijelčič's topic in Tips / Blogs / Tutorials / Videos
Copy&paste bug, sorry. Was OK on the blog, wrong here in the forum. Corrected. Thank you! -
Caching with class variables
Primož Gabrijelčič replied to Primož Gabrijelčič's topic in Tips / Blogs / Tutorials / Videos
It works for our code 🙂 We don't pass large sets through that function and everything is fine. -
Caching with class variables
Primož Gabrijelčič replied to Primož Gabrijelčič's topic in Tips / Blogs / Tutorials / Videos
Exactly - I somehow deleted that line from the gist, while still keeping it in my local copy of the code. 😞 😞 😞 (Actually, this Move should not be 'if'-ed. Just always execute it.) I'll fix my blog, gist example and this post when I come home later today. Thank you for finding the bug! -
High-level abstractions - Difficulties in choosing and using appropriate strategies for solving my task.
Primož Gabrijelčič replied to Shrinavat's topic in OmniThreadLibrary
Pipeline would work as you can run each stage in more than one parallel task (by using .NumTasks). But Parallel.BackgroundWorker is probably more appropriate. -
Was IDE Fix Pack merged into 10.3 release?
-
Watch one task with another - restart if stopped
Primož Gabrijelčič replied to hschmid67's topic in OmniThreadLibrary
This looks like a bug in OTL. Can you please create a small, self-contained, compilable example so I can retest? As a workaround, why do you need Task1 to monitor Task2? This should work equally well: procedure RunTask; begin Task2 := CreateTask( procedure(const mTask: IOmniTask) begin ... end) .OnTerminated(procedure(const mTask: IOmniTaskControl) begin Task2 := nil; RunTask; end); Task2.Run; end; -
Changes in Parallel Library
Primož Gabrijelčič replied to hsvandrew's topic in RTL and Delphi Object Pascal
When I need a busy loop I usually just do a := 1; while not timeout do a := Cos(a); -
Changes in Parallel Library
Primož Gabrijelčič replied to hsvandrew's topic in RTL and Delphi Object Pascal
"Might or might not". Sleep is a good tool to demonstrate a bug. But I agree with you - if it works with Sleep, it still may not work with a high CPU load code. So proving with "Sleep" that the library works is not good enough. OTOH, proving with a high CPU load code that it works is also not good enough. "Unit tests can only be used to prove that a parallel code is NOT working." - me (BTW, I know that we agree here 🙂 I just wanted to state that testing parallel code with Sleep is a perfectly good tool. It is just not good enough.) -
Changes in Parallel Library
Primož Gabrijelčič replied to hsvandrew's topic in RTL and Delphi Object Pascal
Because? Unless the thread pool manager is measuring CPU load, the result should be the same. And if the thread pool manager does that, it is easy to replace the code with a busy loop. As far as my bug hunting in Delphi's TThreadPool went, replacing Sleep(2000) with a 2 second busy loop never changed anything. -
Opinions solicited: Parallel processing to delete 40+Gig file structure?
Primož Gabrijelčič replied to KeithLatham's topic in RTL and Delphi Object Pascal
How do you delete the folder? By deleting files one by one and the removing the parent folder? In that case, you may want to execute cmd /c rmdir /q /s target_folder from your program. Should be much faster. -
Changes in Parallel Library
Primož Gabrijelčič replied to hsvandrew's topic in RTL and Delphi Object Pascal
The biggest problem with PPL (apart from number of terrifying bugs that were only recently fixed) is the annoying and uncontrollable behavior of its thread pool. It will start threads as it seems appropriate, sometimes seemingly without considering min/max concurrent tasks configuration (of which the 'min' part is actually not, as per source, see below). // Returns false if attempting to set a value < 0 or > MaxWorkerThreads. The actual number of pool // threads could be less than this value depending on actual demand. Setting this to too few threads could // be less than optimal resource utilization. function SetMinWorkerThreads(Value: Integer): Boolean; (BTW, the comment suggests that MinWorkerThreads can be set to the same value as MaxWorkerThreads. This is not the case. It must be less than that.) "Annoying and uncontrollable behavior": Sometimes you schedule N threads, then wait, then schedule M (M > N, but M < MaxWorkerThreads) threads, but only N would start. I can repeatedly reproduce this in Tokyo (and Berlin, and Seattle ...). The problem was mostly, but not completely, fixed in Rio. I noticed some problems there, too, but at the moment I don't yet know how to reproduce the problem from scratch.