-
Content Count
247 -
Joined
-
Last visited
-
Days Won
11
Posts posted by Primož Gabrijelčič
-
-
Some additional info can be found here: https://stackoverflow.com/questions/3976610/moving-a-caption-less-window-by-using-a-drag-area.
-
Forgot to write that? Oh, me! 😞
In this case, the code can just assume that the first value in the pipeline is a database name:
function Build_DbInserterStage(const ADatabaseName: string): TPipelineStageDelegateEx; begin Result := ( procedure(const input, output: IOmniBlockingCollection; const task: IOmniTask) var ovIN: TOmniValue; DB: TxxxDatabase; begin DB := TxxxDatabase.Create(); DB.DatabaseName := ovIN.Take; for ovIN in input do begin // ... insert downloaded file end; DB.Commit; end); end;
In more general terms you can declare your special messages which carry metadata (database name) instead of a normal data (to be operated upon). The worker thread can then check the type of the message and react accordingly. You can use TOmniValue's array support for that:
pipeline.PipelineStage[3].Input.Add(TOmniValue.CreateNamed(['Type', 'Config', 'DBName', dbName])); pipeline.Input.Add(TOmniValue.CreateNamed(['Type', 'Data', 'Value', value])); for ov in input do if ov['Type'] = 'Config' then db.DatabaseName := ov['DBName'] else Process(ov['Value']);
-
1
-
-
IOmniPipeline.PipelineStage[num] returns an interface which exposes Input and Output pipeline for that stage:
type IOmniPipelineStage = interface ['{DFDA7A07-6B28-4AA6-9218-59D3DF9C4B8E}'] function GetInput: IOmniBlockingCollection; function GetOutput: IOmniBlockingCollection; // property Input: IOmniBlockingCollection read GetInput; property Output: IOmniBlockingCollection read GetOutput; end; IOmniPipeline = interface function GetPipelineStage(idxStage: integer): IOmniPipelineStage; // ... property PipelineStage[idxStage: integer]: IOmniPipelineStage read GetPipelineStage; end;
You can use them to send data to a specific pipeline stage, for example:
pipeline.PipelineStage[2].Input.Add(42);
First pipeline stage has index 0.
-
Sure, when FPC supports all necessary language constructs.
-
OmniThreadLibrary has many similar constructs. The closes of them is possibly a Pipeline, or a BackgroundWorker, or an Async, depending of what exactly do you want to do with the code.
There's a separate subforum for OmniThreadLibrary here: https://en.delphipraxis.net/forum/32-omnithreadlibrary/
-
New OmniThreadLibrary is out! Get it while it’s hot!
Version 3.07.7 is mostly a bugfix release. It fixes a stupid mistake introduced in version 3.07.6 plus some other minor bugs.
You can get it now on git, download the ZIP archive, install it with Delphinus or with GetIt.
For more information, visit OmniThreadLibrary home page or write your question on the forum.
New features
- [HHasenack] On XE3 and above, TOmniValue.CastTo<T> supports casting to an interface.
- [HHasenack] Implemented Parallel.ForEach(IEnumerator<T>) and Parallel.ForEach(IEnumerable<T>).
Bug fixes
- If additional wait objects registered with RegisterWaitObject were constantly signalled, timers were never called.
- OtlParallel threads were incorrectly scheduled to the main pool instead of GlobalParallelPool unless IOmniTaskConfig.ThreadPool was used. (introduced in 3.07.6)
- Using Parallel.Join, .For, and .ForEach with .OnStopInvoke failed with access violation if Join/For/ForEach was not executed with .NoWait.
- Thread pool creation code waits for thread pool management thread to be started and initialized. Without that, CountQueued and CountExecuting may not be initialized correctly when thread pool creation code exits. [tnx to Roland Skinner]
-
4
-
Class constructors are called when units are initialized, strictly in a single-threaded context.
-
It uses "banker's rounding", after all. 😉
-
2
-
-
http://docwiki.embarcadero.com/RADStudio/en/Declarations_and_Statements_(Delphi)#For_Statements
QuoteFor purposes of controlling the execution of the loop, the expressions initialValue and finalValue are evaluated only once, before the loop begins. Hence, the for...to statement is almost, but not quite, equivalent to this while construction:
begin counter := initialValue; while counter <= finalValue do begin ... {statement}; counter := Succ(counter); end; end.
-
That behavior is correct. `for` loop will execute once with `i` being set to 0.
-
Uwe's post clearly states: HKEY_CURRENT_USER\Software\Parnassus OU\Core
-
1
-
-
Works like a charm! Thank you!
-
1 hour ago, Uwe Raabe said:Would it help to change the registry setting to "$(BDS)\\Experts" and make sure that the correct DLLs reside in the proper places?
Great idea, but unfortunately it doesnt work.
Setting it to "($BDS)\Experts" fails in the same way.
-
10 hours ago, GPRSNerd said:Reason is, that the path to the core dll is common for all installed releases through a setting in the registry:
[HKEY_CURRENT_USER\Software\Parnassus OU\Core]
"Path"="C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\20.0\\Experts"This always points to the last installation.
@David Millington Can you - or Embarcadero - please publish Bookmarks and Navigator 1.6 for older platforms? Or create a version that does not depend on share "Core" DLL? I think the community would very much appreciate it. I know I would.
-
4
-
-
I have C:\Users\gabr\Documents\Embarcadero\Studio\20.0\CatalogRepository\ParnassusCoreEditor-1.0\ParnassusCoreEditor.dll (modified 15.2.2019)
and
C:\Users\gabr\AppData\Roaming\Parnassus OU\Common\ParnassusCoreEditor_XBerlin.dll (modified 20.5.2016)
So I don't see why the 1.6 install in Rio would break Berlin at all 😞
-
Installed Bookmarks & Navigator in Rio.
Now my Berlin reports "Access violation at address 07E8D047 in module 'ParnassusCoreEditor.dll'. Read of address 00000000." when I start the IDE. I get the same error when loading a project and then Bookmarks doesn't work.
I also get a bunch of errors when I open a form unit and then I get into "Access violation at address 20837CFB in module 'coreide240.bpl'. Read of address 00000018." which repeats indefinitely.
😠
I have Bookmarks 1.5.1 installed in Berlin.
Is there anything I can do to have working Bookmarks both in Berlin and Rio?
-
Indeed, I'm working on it. Now that I have finished my book, OTL will again become a top priority side project.
It's hard to tell how much work is yet to be done as at the moment some very basic parts are still missing and I don't know how much time I'll need for them.
A crowdfund would be nice - one where you can give me additional time inside a day. 30h per day would be good to have 😉
-
5
-
1
-
-
Nice additions, Andrea 🙂
Whether for the good or bad, who can tell 😉
My initial approach was trying to get too much from LiveBindings anyway (intentionally). Your changes are definitely in direction of making my messy code more maintainable so they make it better. They, however, introduce more code, so from my original viewpoint they make it worse. 😉
-
1
-
-
On 2/8/2019 at 7:46 AM, Shrinavat said:@Primož Gabrijelčič Do you have any progress for this issue fix? There are no new commits on github. Current workaround with using extra variable is not very elegant, although it works.
No, and don't expect one soon. There are more urgent issues to be fixed before.
-
1
-
-
Great that you got it working!
Re 4000 tasks I was thinking more about - what if you set up a Parallel.BackgroundWorker with multiple workers and then schedule work units to it? You would have one always running execution engine (i.e. background worker) and instead of 4000 tasks you would have 4000 work units.
-
Got it.
type POmniValue = ^TOmniValue; TOmniValue = record private FOwnedObject: IAutoDestroyObject; function GetAsOwnedObject: TObject; procedure SetAsOwnedObject(const Value: TObject); public class operator Implicit(var ov: TOmniValue): POmniValue; static; property AsOwnedObject: TObject read GetAsOwnedObject write SetAsOwnedObject; end; IWorkItem = interface ['{7C583FC8-90DD-46A5-81B9-81B911AA1CBE}'] function GetResult: POmniValue; procedure SetResult(const Value: POmniValue); property Result: POmniValue read GetResult write SetResult; end; TWorkItem = class(TInterfacedObject, IWorkItem) strict private FResult: TOmniValue; strict protected function GetResult: POmniValue; procedure SetResult(const Value: POmniValue); public destructor Destroy; override; property Result: POmniValue read GetResult write SetResult; end; class operator TOmniValue.Implicit(var ov: TOmniValue): POmniValue; begin Result := @ov; end; function TWorkItem.GetResult: POmniValue; begin Result := @FResult; end; procedure TWorkItem.SetResult(const Value: POmniValue); begin FResult := Value^; end;
It's quite possible that this breaks quite easily, though, as this solution looks quite fragile to me. It is simple and efficient, though.
-
Yes, it is definitely not a fast solution. It is elegant for the user, though.
-
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.
-
1
-
-
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 😞
Hands-On Design Patterns with Delphi
in Tips / Blogs / Tutorials / Videos
Posted
Original post: https://www.thedelphigeek.com/2019/02/design-patterns-with-delphi-book.html
Hurrah, hurray, my third book is here! It’s called Hands-On Design Patterns with Delphi and (just like my first book) I wrote it for Packt Publishing. (The second book was self-published and I expect the fourth one to be, too.)
As the name says, “Design Patterns with Delphi” deals with design patterns. It is a bit different from most of design pattern books and websites you will find on the Internet. Case in point A: There are no UML diagrams. I don‘t speak UML. Tried to learn it few times but for some reason the whole concept doesn‘t agree with me. If you like diagrams, don’t fear though. Any book on design patterns - and most websites covering that topic - will gladly show how any design pattern can be diagrammed. That, however, is not important and should not govern your decision to buy the book.
More important is case in point B: This book speaks Delphi. All the examples are written in Delphi and language features are used to the full. I also covered few less known Delphi idioms in separate sections. You’ll still be able to follow the discussion even though you may program in a different Pascal dialect.
There’s also case in point 😄 Examples make sense. I deeply dislike classical design pattern examples of the “And then we want to write this program for different toolkits and it should also be able to draw circles, not only squares” kind. Euch! I tried to find a good example for each design pattern. Admittedly, I ended with few examples that draw triangles and squares on screen (mostly because some patterns were designed specifically for solving such problems), but most of them are of a more practical nature.
This book covers all three classical design pattern categories - Creational patterns, Structural patterns, and Behavioral patterns. It also discusses patterns from the newer Concurrency patterns category. At the end I threw in some borderline-pattern(ish) topics and ended with a discussion of few patterns that cannot be strictly classified as “design” patterns.
In this book you’ll find:
An introduction to patterns. Exploration of design principles, design patterns, and idioms. A mention of anti-patterns. A short description of most important design principles. Delphi idioms: creating and destroying objects.
Creation patterns part 1. Singleton. Dependency injection. Lazy initialization. Object pool.
Creation patterns part 2. Factory method, Abstract factory, Prototype, Builder. Delphi idioms: Assign and AssignTo.
Structural patterns part 1. Composite. Flyweight. Marker interface. Bridge. Delphi idioms: comparers and hashers.
Structure patterns part 2. Adapter. Proxy. Decorator. Facade. Delphi idioms: replacing components in runtime. Also: helpers.
Behavioral patterns part 1. Null object. Template method. Command. State.
Behavioral patterns part 2. Iterator. Visitor. Observer. Memento. Delphi idioms: for .. in.
Concurrency patterns part 1. Locking. Lock striping. Double-checked locking. Optimistic locking. Readers-writers lock. Delphi idioms: tasks and threads. Also: bitwise operators.
Concurrency patterns part 2. Thread pool. Messaging. Future. Pipeline.
Writing Delphi programs. Event-driven programming. Actions. LiveBindings. Form inheritance. Frames. Data modules.
Wrapping it up. Exceptions. Debugging. Functional programming.
I hope you will like this book and learn a lot from it. I know I did during the nine months I spent writing it. And if you find any bug in the code, let me know so I can correct it in the second release!