Jump to content

Dalija Prasnikar

Members
  • Content Count

    1111
  • Joined

  • Last visited

  • Days Won

    96

Everything posted by Dalija Prasnikar

  1. Dalija Prasnikar

    Creating FMX controls in a background thread

    Plenty. User interfaces in general (not just Delphi) are not thread-safe. Thread safety comes with hefty price. You would have to lock just about everything and it would significantly slow down the UI. Also, UI controls are complex and have plenty of interactions. Due to that complexity, making UI thread-safe would be complicated and error-prone. Not only that, but UI needs to interact with OS layer where UI controls are also not thread-safe as such where you cannot access the same control from different threads. That means if you would construct one control in background thread to be used in main thread afterward, not only you would have to make sure that interaction with Delphi UI side of controls have to be thread-safe, but control would have to avoid triggering any code that interacts with OS part which is almost impossible. UI is not thread-safe by design and that is something that will not change as it is not practical nor beneficial. There are some parts around handling images that could be fixed to fully support processing images in background threads and then passing them to the UI for presentation.
  2. It takes 10 minutes to create such generator. I have few that generate boring code based on my coding patterns. I just need to write field declaration, copy-paste that to generator and I get all property declarations and assign method out of it. Yes, I need to adjust some of them afterwards, depending on their type, but that is only because my generator is extremely dumb parser and I never bothered to improve it as I don't need it that often. I mean, if you find AI useful for some tasks, then by all means use it. But it is not a magical tool, and it has serious limitations. If you are aware of those, then you can get the most of it, but don't expect any intelligent solutions out of it.
  3. Dalija Prasnikar

    Nested TParallel.For: Immediate deadlock

    The problem happens when outer For loop consumes all available threads and hits maximum where no new threads are being allocated for newly requested task. And then if inner tasks cannot get free thread to run, they cannot complete their job. I have test case that will break more easily as number of needed threads is higher, and sleep also increases the time inner thread runs and gives more time for outer for loop to consume all available threads. Using separate pool for inner for loop solves the problem. This can still be an issue if you have code that indirectly uses nested parallel loops. begin var counter := 0; var pool := TThreadPool.Create; const COUNT = TThreadPool.Default.MaxWorkerThreads * 4; TParallel.For( 0, Pred(count), procedure(i: Int64) begin TParallel.For( 0, Pred(count), procedure(i: Int64) begin TInterlocked.Increment(counter); Sleep(10); end , pool); end ); Writeln(counter); Readln; end. Probably the best solution for parallel for loops that can spawn too many tasks would be to create dedicated thread pool for each loop. The cost of creating a thread pool is not big when dealing with longer running tasks. And for fast running tasks, like in this example, parallel loop is overkill anyway as it can run slower than simple for loop in single task.
  4. Dalija Prasnikar

    try... finally on Mac

    Inline behaves as if you have written the code directly within the try..except method. Just like double nesting does not help with the inlined procedure it will not help with any other code that is written directly in try..except block. Only wrapping the code that can cause exception in additional function, procedure or method is the solution.
  5. Dalija Prasnikar

    try... finally on Mac

    If the G! is inlined then exception will not be caught by second level try..except block. It can only be caunght by exception handler outside the method where exception happens. var P: ^Integer = nil; procedure G1; inline; begin P^ := 42; end; procedure TForm1.G2; begin try try G1; except Memo1.Lines.Add('Inner'); end; except Memo1.Lines.Add('Outer'); end; end; procedure TForm1.Button1Click(Sender: TObject); begin try G2; except Memo1.Lines.Add('Proc'); end; end; In other words, in above code exception will be caught by exception handler around G2 -> Proc If we remove inline directive then exception will be caught by Inner exception handler. I don't know whether LLVM can automatically inline functions that are not explicitly marked for inlining, but I would expect that we shouldn't worry about that as this would break exception handling not only for Delphi, but for other languages, too.
  6. Dalija Prasnikar

    try... finally on Mac

    Don't worry, it was evident that this was just an example to show the failure. Obviously in real code one would not set object to nil and then use if Assigned() to check whether object is nil before using it. But if you have scenario where some function call can return nil object as valid response - for instance finding object that satisfies condition in a collection, and returns nil if the appropriate object is not found, then you have to check for nil before using it. Once you have valid object, calling methods on it, even if they raise exceptions will be caught by surrounding exception handler. Again, in such cases you will be calling some library function, and unless you are calling something on nil object this will be fine. The potential issues may arise if the library itself (Delphi ones) is not written with LLVM based compilers in mind, where some exceptions will won't be caught by appropriate exception handlers within the library code. If that happens then the library code has to be fixed, you cannot solve the problem from your code.
  7. Dalija Prasnikar

    try... finally on Mac

    This issue happens on all LLVM backed compilers because LLVM is not capable of catching hardware exceptions unless exception happens within another function. You find more information on my blog post https://dalijap.blogspot.com/2018/10/catch-me-if-you-can.html I never got around to write the sequel, but the implications is that literally anything that all exception handling implicit or explicit is broken in such situations. The solution is that you either wrap your code in separate function that will not have any exception handling within, and then the caller will be able to catch and handle raised exceptions. Another way of solving issues is to avoid code that can trigger such hardware exception and raise Delphi exception if code does not satisfy some requirement as explained in https://docwiki.embarcadero.com/RADStudio/en/Migrating_Delphi_Code_to_Mobile_from_Desktop#Use_a_Function_Call_in_a_try-except_Block_to_Prevent_Uncaught_Hardware_Exceptions So in the context of your example, you should either check whether object is nil before trying to use it (this would actually be general advice, as accessing nil object, depending on the code, on Windows does not guarantee that you will get AV). Note. I don't know what exactly following quote from documentation about macOS means: "structured exception handling (__try/__except) is not available". Linked page talks about hardware exceptions, but I am not sure whether there are some other implications here besides what I said in context of LLVM. At the moment I don't have my development environment set up in a way that would allow me to verify behavior on Mac. While bugs are always possibility, RTL appropriately handles hardware exceptions in cross-platform code. I removed wrong duplicates and added appropriate one.
  8. Dalija Prasnikar

    How to free object compiled to Linux

    On Windows Delphi uses FASTMM memory manager and on Other platforms it uses POSIX memory manager. I am not that familiar with inner workings of a POSIX memory manager, but FASTMM allocates larger chunks of memory from the OS which is then used for sub-allocating object instances and other heap based data. When you release an object, data in its memory location can be still intact and accessing such data does not always crash. In such cases memory is held by FASTMM so there will be no crash in the OS side because for the OS it is valid memory allocated by the program. If you use FASTMM in full debug mode during the development, then accessing such invalid object will be noticed by FASTMM and shown as error.
  9. Dalija Prasnikar

    How to free object compiled to Linux

    I cannot verify the issue at the moment, but since TJsonTextReader uses TStringReader it might be better to reverse the releasing order. It is likely that TJsonTextReader destructor is accessing the TStringReader instance during destruction process. Such code would also be wrong on Windows, but you are just lucky that it does not fail there. LJsonTextReader.Free; LStringReader.Free;
  10. Dalija Prasnikar

    Need inline InterfacedObjects to be freed?

    Compiler cannot give you appropriate hint at that place. The problem is that it doesn't know whether you need to use interface reference or not because some classes that have interfaces have reference counting disabled and are used through object references. If compiler would give a hint that would result in many false positives and at the end such hints would be useless. This is similar situation as the one where developer declares regular variable, but uses wrong type. There are no hints for such scenarios either.
  11. Dalija Prasnikar

    Need inline InterfacedObjects to be freed?

    The inline variable in question will be of type TCar as its type will be inferred from type used in constructor: TCar. In such code where object instances are reference counted, you will need to explicitly specify correct type: ICar because reference counted instances need to be stored in interface references for proper initialization of reference counting mechanism. var car: ICar := TCar.Create;
  12. I already checked. Domains where it might work better are in a creative domain where there are no right or wrong answers, but then it is just a parrot that repeats someone's thoughts. When people talk about AI they like to focus on intelligence. But ChatGPT is just a language model, with some corrective mechanisms on top. What it means? It means there is no intelligence involved. It is just fancy "text completion" model that uses probability to determine which word should follow next in some sentence. Even when the model grows, and its probability analysis improves, it is still just dumb "text completion" It will never be able to reason about what it writes. And again, it may get better in avoiding ridiculous mistakes, but you are still stuck with original issue: you cannot trust the information it gives you, because it may not be correct and you will not be in position to realize that.
  13. Main problem wit ChatGPT is that if you are asking about something you don't know well, it can lead you in completely wrong direction and you will never know it because you lack the expertise. And it will lead you there with a confidence of a master. And it is not wrong only occasionally, it is wrong most of the time. If you like wasting your time on wrong leads and hints, then it is absolutely the right tool for any job.
  14. I have published initial release of NX Horizon Event Bus for Delphi as Open Source on GitHub. Features: implements the publish/subscribe pattern, decoupling publishers and subscribers events are categorized by type any Delphi type can be used as an event supports four types of event delivery: synchronous, asynchronous, synchronous in the context of the main thread, and asynchronous in the context of the main thread provides generic record and reference-counted class wrappers for easier usage and management of existing types as events simple in both implementation and usage fast full thread safety https://github.com/dalijap/nx-horizon
  15. Dalija Prasnikar

    ANN: Open Source Event Bus NX Horizon

    I was already working on my event bus when I discovered DEB. I would still work on mine even if I knew about DEB sooner, because I also wrote about it in my book and I cannot reason about other people's thought process It is also published as part of book code examples, but it is a feature that deserves separate repository not tied to the book. When it comes to why DEB would not fit my purpose (if I ignore the book part), is that it has more complicated code and more features that don't necessarily bring anything of value to me (for instance, using attributes for setting subscriptions), but on the other hand have big impact on performance. My even bus also supports all types as messages, so there is additional performance boost and avoiding unnecessary memory allocations when message fits into integer or small record type. And at last, my even bus has waitable subscription, so you can wait that all dispatched messages are being fully processed. This is critical feature for more complex cleanup scenarios - yes, it can also be achieved through other means, but it is easier when it is built in feature, and I use it a lot. And the most personal reason is that my code is more compatible (similar setup and calls) with my old thread-unsafe observer framework, and I can more easily and gradually refactor old code to using new one.
  16. Dalija Prasnikar

    Delphi beta testing a "premium" privilege?

    It is not pay to see the roadmap. There is no longer a roadmap as such. But those that participate in beta testing have a bit more information about what is coming next in immediate and for some parts the release after that sooner than it is publicly available.
  17. Dalija Prasnikar

    Delphi beta testing a "premium" privilege?

    Don't ask me. I don't know why.
  18. Dalija Prasnikar

    Delphi beta testing a "premium" privilege?

    Because their marketing database is not connected to customer database.
  19. Dalija Prasnikar

    Delphi beta testing a "premium" privilege?

    Currently one of the greatest is that when it chokes on something it needs to be killed and restarted. This can be done more easily by creating menu item in IDE. See https://stackoverflow.com/q/74164165/4267244
  20. Dalija Prasnikar

    Delphi beta testing a "premium" privilege?

    Trust me. Number of people testing is the least problem right now. One of the issues with LSP is that it is a huge endeavor. Which on its own would be such an issue if they could have left the old one running beside it like in Sydney. However, old tech interfering with LSP integration and they had to remove it.
  21. Dalija Prasnikar

    Delphi beta testing a "premium" privilege?

    It seems like Premium subscription gives you "advanced" beta access. For Standard it says there is access to beta for each major version release. So reading between the lines and knowing that current beta is just an update, this might mean that only Premium subscribers will have access to this beta. https://www.embarcadero.com/support
  22. Dalija Prasnikar

    No one can help

    Then the problem is not in this particular code but all the other code that consumes all available memory. The general advice for reducing memory footprint I gave earlier still stand. Yes, using separate applications will help because each will have its own memory limit if they are running on 64-bit OS.
  23. Dalija Prasnikar

    No one can help

    The question is whether or not you have done that correctly. The moment you write the data to file, you need to release memory of all the temporary data that was used in that process before you try to load that into control. MyMemStream := ProjectsFDTable.CreateBlobStream(ProjectsFDTable.FieldByName('Description'),bmRead); try TMemoryStream(MyMemStream).SaveToFile('t.txt'); // using absolute path is preferred finally MyMemStream.Free; end; Memo1.BeginUpdate; try Memo1.LoadFromFile('t.txt'); finally Memo1.EndUpdate; end;
  24. Dalija Prasnikar

    No one can help

    Don't use memory stream to load data to rich edit. Create temporary file and write the data into that file and then load the data from the filestream. However, no matter what you do, at some point you will run into memory issues with 32-bit application if your application consumes a lot of memory. I suggest you switch to 64-bit. If you cannot switch to 64-bit, then the only other option is optimizing other parts of your application to reduce overall memory usage. First step for optimizing would be getting rid of all memory leaks - they can cause fragmentation which can be a huge problem. Next, reducing total memory allocation, by releasing anything that is not used at the time. Be careful with creating local components that have owner which you don't explicitly free. They will not show as memory leaks, but every time you call such method your memory consumption will increase. If that does not help, then you can try reducing memory load by avoiding default string type which is Unicode since D2009 (you haven't said which Delphi version you use) and use UTF-8 encoded strings - UTF8String and convert to Unicode only when you need to display data to the user - this is really the last option as you may need to write a lot of supporting code to avoid accidental conversions to and from Unicode strings as they will slow your application down and use extra memory in the process.
  25. Dalija Prasnikar

    Detect when/what makes a tcomponet descendent is made NIL?

    What is main? You are most likely corrupting a memory by accessing same data from main thread and background thread. Also you shouldn't work with any visual control from the background thread without calling the TThread.Synchronize or TThread.Queue Also you are working with pointers, so it is possible that you are accidentally overwriting something.
×