Jump to content

Dalija Prasnikar

Members
  • Content Count

    729
  • Joined

  • Last visited

  • Days Won

    63

Everything posted by Dalija Prasnikar

  1. Dalija Prasnikar

    File-> Open recent: way off the top of the screen

    Yes, there is. I forgot about that. I have a need for large number of projects and files and when I get into a trouble with the menu, it is easier for me to remove specific files than to have smaller number of files remembered.
  2. Dalija Prasnikar

    File-> Open recent: way off the top of the screen

    This issue seems to happen when you have too many files in the recent menu. Open properties - most bottom option in the menu and delete few files (how many depends on the size of your screen) from the recent list. That should fix it. If it is not fixed, you will need to remove more files. Reported as https://quality.embarcadero.com/browse/RSP-36702
  3. Dalija Prasnikar

    Parallel processing question

    Instead of anonymous methods, you can also use plain TNotifyEvent and pass list item as Sender. Also if you don't like the code in completion handler because of TThread.Queue, this call can be moved to UpdateItem. There are many ways to write this functionality, this is just one.
  4. Dalija Prasnikar

    Parallel processing question

    But it is completely decoupled in that code. The only connection is in attached completion handler that can hold any kind of code and is not part of processing class.
  5. Dalija Prasnikar

    Parallel processing question

    Yes, you can use that approach, but it is not flexible because your processing function depends on the specific UI type. I wouldn't create task inside Execute method because processing functionality itself should be implemented as clean synchronous code - that gives you more flexibility to combine its functionality as needed. I would use something like: TMyClass = class public procedure Execute(OnCompleted: TProc); end; procedure TMyClass.Execute(OnCompleted: TProc); begin // process data //... if Assigned(OnCompleted) then OnCompleted; end; procedure TMyForm.ProcessItem(li: TListViewItem); begin TTask.Run( procedure begin TMyClass(li.Data).Execute( procedure begin TThread.Queue(nil, procedure begin UpdateItem(li); end); end); end); end; procedure TMyForm.UpdateItem(li: TListViewItem); begin li. ... end; procedure TMyForm.ProcessView; begin for var li in lview1.Items do begin ProcessItem(li); end; end;
  6. Dalija Prasnikar

    Parallel processing question

    You are right that the processing logic and updating UI don't belong together. When I have processing functionality as part of the class (and I usually do) I also declare completion handlers in that class. And then you can easily attach any kind of additional logic when processing is finished - including updating UI. The most important part is that all individual pieces of code can be easily unit tested (except for UI) and that there is minimal gluing code where you can make mistakes when you put all of the code together.
  7. Dalija Prasnikar

    Parallel processing question

    That is true, there is no OnCompleted event You can do that inside the task code. You can either send message with some messaging system or call appropriate code directly (make sure it is synchronized with the main thread for UI interaction). To free thread for further processing it is better to use TTask.Queue instead of TThread.Synchronize, but if you need to perform some cleanup, Synchronize will do as long as it is not too slow. Something like: TTask.Run( procedure begin // your background work ... // task is completed TThread.Queue(nil, procedure begin // update the UI end); end);
  8. Dalija Prasnikar

    When free isn't free anymore..

    Since Delphi 10.4 memory management across all platforms has been unified. That means Free and FreeAndNil behave on android just like then always behaved on Windows. There is still DisposeOf, but it just calls Free now. You can change those calls, but you don't have to. The only place where you can have leaks on Android due to this change is if you have been relying on ARC to release your objects and you were just assigning nil to them or you were just letting them go out of scope.
  9. Because of this https://stackoverflow.com/a/42305385/4267244 But, once you have determined your weak reference is valid, you can take strong reference out of it. Once you have strong reference you can do what you need with that reference. procedure TObjectWithTest.QueueCallSafe([weak]AInterface: ITest); begin TThread.ForceQueue(nil, procedure var Strong: ITest; begin if AInterface = nil then ShowMessage('nil') else begin Strong := AInterface; ShowMessage('not nil'); end; end); end; Again, this only works if there are no background threads involved.
  10. Depends what you mean by fixing it? If you are fine that under some circumstances you will get nil inside QueueCallSafe and you check for such situation then you have fixed it. Be aware that this code will only work if object is released in the context of main thread - Obj.Free line. If you have that kind of code in some background thread then code in QueueCallSafe will not be safe.
  11. Dalija Prasnikar

    Long term availability of Community Edition

    There is no guarantee it will be available in the future. We can only hope it will be
  12. Dalija Prasnikar

    SudokuHelper - Example for uncoupled design via interfaces

    Yes.... forget the fake interface approach... brain fart...
  13. Dalija Prasnikar

    SudokuHelper - Example for uncoupled design via interfaces

    Possible solution for interface problem would be using fake interface instance as magic value as reference counting on that would not cause any problems (Note: I haven't tested such solution). function NopAddRef(Inst: Pointer): Integer; stdcall; begin Result := -1; end; function NopRelease(Inst: Pointer): Integer; stdcall; begin Result := -1; end; function NopQueryInterface(Inst: Pointer; const IID: TGUID; out Obj): HResult; stdcall; begin Result := E_NOINTERFACE; end; const FakeInterfaceVTable: array [0 .. 2] of Pointer = (@NopQueryInterface, @NopAddRef, @NopRelease); FakeInterfaceInstance: Pointer = @FakeInterfaceVTable; At this point, solution with lock seems like simpler approach if it makes sense to avoid unnecessary instance construction. On the other hand, if you are to write some universal lazy initialized container that will work on different types, then this solution even though more complicated would pay off.
  14. Dalija Prasnikar

    SudokuHelper - Example for uncoupled design via interfaces

    It will crash at FSingleton := TSingleton.Create during assignment. At that point FSingleton value is pointer(1). FSingleton is interface, and assigning new value will try to call _Release on any non-nil old value to maintain appropriate reference count and that old value is invalid address.
  15. Dalija Prasnikar

    SudokuHelper - Example for uncoupled design via interfaces

    That is better solution (it would require additional if to prevent calling CompareExchange for every access, similar to original example (full code)) , but it does not work with interfaces. Your example used additional lock, so it wasn't really clear what you are objecting to. Also, with lazy initialization code path where possible unnecessary object construction happens is extremely rare situation and even if it does happen lock in memory manager not something that would bother me. Because it happens rarely, even cost of explicit lock is negligible so I never used that "potential" performance issue as something worth measuring and proving which solution is faster. The only considerable argument is how costly is the construction of the object that might get discarded, but using lock in memory manager is a poor way to prove that point.
  16. Dalija Prasnikar

    SudokuHelper - Example for uncoupled design via interfaces

    InterlockedCompareExchangePointer is part of Windows API. AtomicCmpExchange is added to provide cross-platform support. There is also TInterlocked class in System.SyncObjs that implements various static functions for performing interlocked operations, including CompareExchange that basically calls AtomicCmpExchange, but it is more convenient to use for some types.
  17. Dalija Prasnikar

    SudokuHelper - Example for uncoupled design via interfaces

    And how exactly would you do that in this scenario? Not to mention that you are opposing simple full pointer exchange because it is too "clever", and your solution would be bit fiddling. Comfortable, prefer, personally use... those are all the same reasons, just different words. You are reading into words way too much. You don't want to use something because you have subjective reasons. I have no problem with that and I am doing the same in many places. The only reason why am I here objecting, is you saying this is not good pattern and this is not true and it sends wrong message to others that are not familiar with this kind of code. By you saying this is bad code, someone else might avoid such coding pattern because they will wrongly think it is a bad one. The only place where I wouldn't use this pattern is in places where constructed object is extremely heavy and where constructing object that would possibly be immediately discarded would consume plenty of resources or would take a lot of time. I already said why it is good, but I will repeat it. It is lock-free, so the whole operation can be done with single reference (I am not talking about local variables, but broader scope where final reference is declared). There is no additional, separate entity involved. That is reason enough.
  18. Dalija Prasnikar

    SudokuHelper - Example for uncoupled design via interfaces

    It is still separate entity. I don't mind you or anyone else writing code they are more comfortable with. However, I will firmly defend this pattern as good code simply because it is. All lock-free code is "clever", there is no way around it and this is the simplest pattern as it gets for lock-free. And this pattern is also recognized and used across different languages. For anyone that wants to learn more and get out of their comfort zone, this is a good example to learn from.
  19. Dalija Prasnikar

    SudokuHelper - Example for uncoupled design via interfaces

    The critical section or any other kind of lock requires another object that needs to be constructed and maintained separately for no reason. There is no need for introducing locks of any kind here. This is not only working code, but also good code for such situation.
  20. Dalija Prasnikar

    SudokuHelper - Example for uncoupled design via interfaces

    It is thread-safe. This is commonly used pattern for thread-safe lazy instantiation.
  21. Dalija Prasnikar

    My Experience with D10.4

    We all use what works for us. I used Delphi 7 for a long time. You cannot directly compare Android Studio and Delphi. In Android Studio, different parts of the whole toolset are more pluggable and exchangeable. In Delphi main problem is that IDE and core frameworks are firmly tied together. Because changes in platforms often require changes in frameworks - RTL and FMX, they cannot be patched unless changes are limited to implementation parts of the units. So you cannot use one version of the IDE with other version of the frameworks. Also debugger and compiler, are more tied with the rest of the toolset (even though more easily "patchable") than this is the case with Android Studio. Again, without going into specific issues which may be more or less problematic depending on your code, but if you want to develop and release applications for non Windows platforms, you need paid version with subscription. Whether this is an option or not, everyone needs to decide for themselves. Only you know what are the upsides and downsides in your case. Nobody else can make that decision for you. I wish Delphi would be better option and would have less issues, but that does not depend on me or any of us here.
  22. Dalija Prasnikar

    My Experience with D10.4

    That helps with future releases, it doesn't help for backporting changes to existing release. I am not saying that it makes it impossible, but it depends on the actual problems. There were similar fixes done in the past when it was possible to fix parts of the toolset. I also know for sure that sometimes some issues occur in late beta stages when Apple (usually there is more problems with iOS and macOS) reorganizes something that does not have direct impact on native toolset users, but it breaks 3rd party ones.
  23. Dalija Prasnikar

    My Experience with D10.4

    I agree with that. Now, without going into whether Embarcadero is currently giving stable updates or not at the end of the line... In reality stability is possible only on Windows and Linux platforms because those platforms are stable enough. And even on Windows there will be issues in releases when major Windows version changes or some larger feature is introduced. Not all such compatibility issues can be easily backported without making breaking interface changes. On Android, iOS and macOS situation is completely different. New major OS versions are released on yearly basis, breaking havoc in both backward compatibility and ability to run applications on new OS versions. Often even building applications with new tools required will be broken. Porting back is often mission impossible. Delphi IDE is highly integrated environment and you cannot just easily swap and update only some parts that are broken. For those fast moving platforms only viable option is moving forward, having active subscription and participating in beta testing when it is publicly available. Or using other toolsets if Delphi does not fit well for certain use cases.
  24. Dalija Prasnikar

    Many TTasks

    Generally, you don't have to worry about that. The pool handles number of threads for you, depending on minimum and maximum number of threads set for particular pool, and how much is system stressed out (busy) at the time. Only if you see some visible performance issues - tasks don't run in expected time frame or you are not utilizing resources as much as you could (you have too many slow IO bound tasks) you should try to optimize minimal and maximal number of threads per particular thread pool. The only next possible thing you need to worry about (again you need to test the real life scenario) is flooding the task queue with extremely large numbers of tasks at once (probably thousands) where growing task queue can pose a problem.
  25. Dalija Prasnikar

    Many TTasks

    Wild guessing: Someone mixed up number of cores with number of logical processors where hyperthreading allows two threads per physical core. CPUCount returns number of logical processors so doubling that is wrong. On other hand, probably more accurate guess would be that this number is used as some sort of "best" default because not all tasks are CPU bound, and for IO bound tasks more threads than logical CPUs gives better performance. Optimizing number of threads is not always easy as it is highly dependent on actual tasks.
×