Jump to content

Dalija Prasnikar

Members
  • Content Count

    1129
  • Joined

  • Last visited

  • Days Won

    102

Everything posted by Dalija Prasnikar

  1. 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);
  2. 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.
  3. 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.
  4. 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.
  5. 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
  6. Dalija Prasnikar

    SudokuHelper - Example for uncoupled design via interfaces

    Yes.... forget the fake interface approach... brain fart...
  7. 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.
  8. 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.
  9. 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.
  10. 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.
  11. 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.
  12. 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.
  13. 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.
  14. Dalija Prasnikar

    SudokuHelper - Example for uncoupled design via interfaces

    It is thread-safe. This is commonly used pattern for thread-safe lazy instantiation.
  15. 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.
  16. 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.
  17. 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.
  18. 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.
  19. 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.
  20. Dalija Prasnikar

    Many TTasks

    Tasks use threads from associated thread pool. If you don't explicitly specify thread pool, default one will be used. Maximum number of threads each pool can start (use) can be modified for each pool, and default value is number of CPUs * 2. (This value is valid for Delphi 11, it is possible that it was some other value in previous versions) So if you have 8 CPUs and you start 9 tasks, they will start 9 threads running in parallel, unless one of the tasks manages to finish before all 9 tasks are queued to tasks work queue. You should always assume that tasks will run in parallel, in other words you cannot count on particular task finishing before some other task.
  21. Dalija Prasnikar

    Asynchronous Programming Library

    IAsyncResult as abstract interface is not a problem. It is not a problem that you can choose the async backend. It is a problem because that backend support is directly backed inside the class that needs to do some work. It is a problem because that is all done via inheritance on classes that should not care about all that. It is abstraction imposed on a wrong level. Not necessarily. It is difference between debugging and inspecting your code, vs landing on some irrelevant framework pieces to inspect what is happening and where you have particular problem. Try debugging this, where it is questionable will you even land on RequestCompleted handles in case of exception in the request procedure TMainForm.Button1Click(Sender: TObject); begin HttpClient.Asynchronous := True; HttpClient.Get('http://httpbin.org/get'); end; procedure TMainForm.HTTPRequestRequestCompleted(const Sender: TObject; const AResponse: IHTTPResponse); begin TThread.Synchronize(nil, procedure begin Memo.Lines.Add(AResponse.ContentAsString); end); end; versus debugging this procedure TMainForm.Button1Click(Sender: TObject); begin TTask.Run( procedure var Client: THTTPClient; Response: IHTTPResponse; begin Client := THTTPClient.Create; try Response := Client.Get('http://httpbin.org/get'); TThread.Synchronize(nil, procedure begin Memo.Lines.Add(Response.ContentAsString); end); finally Client.Free; end; end); end; Yes, the second example is longer, but it is all in code and does not require any design time wiring. Another problem here is that because THttpClient implements support for IAsyncResult, it is rather complex class. So stepping into such code regardless of how you ended up there will be hard to follow. Without IAsyncResult that class could be much simpler not just to debug and understand, but also easier to maintain.
  22. Dalija Prasnikar

    Asynchronous Programming Library

    Low code is still a thing, or at least that is what "marketing" is selling to us as greatest feature ever. It may be good for non programmers that want to put few things together, but it is really bad for any even remotely complex application. The fastest way to sink an application is to drown it in low code. I had my share of bad design choices some ten years ago... following similar route - slap everything on TComponent and drag and drop design... I am still maintaining that crap and I cannot easily untangle the mess.... I wish someone hit me on the head back then, it would spare me a lot of trouble.
  23. Dalija Prasnikar

    Asynchronous Programming Library

    Thanks! Look at the dates... he wrote about it in 2008 and the thing was included in 2015 in XE8. Why I have the feeling it was added just to add some check mark on number of new features, without thinking about the impact. At that point having proper cancellation token would be more useful feature. How is this useful in combination with PPL I still cannot figure out. Proof of concept is one thing, imposing it on TComponent is another. If it would be in domain of helper methods, then it would probably be more flexible (adjusting the behavior through inheritance is very rigid) Of course, I understand why it was implemented directly... because we can only have single helper in scope Maybe, it is handy for some quick RAD kind of development, where you need to bang up some example code fast and you need to make the application responsive. One place I know this is used is in System.Net. But, have you ever tried debugging such asynchronous HTTP requests. It is mission impossible, you have to jump through the hoops not knowing where you can safely put your breakpoint to land on some code you need to inspect because it is buried deep. Not to mention that handling request and response code is broken down scattered around in order to satisfy BeginInvoke/EndInvoke pattern. And if you take the look at the THTTPClient declaration, with zillion various Begin... methods, it becomes more obvious that implementing asynchronicity on this level is not the best idea. It brings needles complexity. Asynchronous frameworks should be implemented as wrappers around code and tasks (like PPL), not be implemented on the same level (from within the class that performs some operation). This simply does not scale well.
  24. Dalija Prasnikar

    Is Delphi's HTTPRIO thread-safe?

    No. When you use it, even if you don't change the properties, there are other state (encapsulated data) changes happening and this is where multiple threads can interfere with each other.
  25. Dalija Prasnikar

    Asynchronous Programming Library

    Nope. Frankly, it is abomination. My primary objection is that it slaps control flow into TComponent where it does not belong. TComponent is not thread safe class and asynchronous operations and multithreading imposed on that level open recipe for disaster. It does not give you more control, it takes it away from you and it is overly complicated. Maybe there are some small use cases, but I still haven't found any. At the same time we don't have cancellation token implemented in PPL which desperately needs it. Good implementation of cancelation tokens could then be used in other code even asynchronous one that does not run in threads. I have no idea what is original intent behind that library, so maybe I am missing something obvious.
×