Jump to content

Dalija Prasnikar

Members
  • Content Count

    1062
  • Joined

  • Last visited

  • Days Won

    91

Posts posted by Dalija Prasnikar


  1. 10 hours ago, Attila Kovacs said:

    "Most obvious problem is that such code becomes re-entrant."

    Which code? The one starts the blocking loop or the one starts the thread? They have to backed up both. Don't they?

     

    The code where you call Application.ProcessMessages

     

    procedure TMainForm.BtnClick1(Sender: TObject);
    begin
      DoFoo;
      DoBar;
      DoFork;
    end;
    
    procedure TMainForm.BtnClick2(Sender: TObject);
    begin
      DoFoo;
      Application.ProcessMessages;
      DoBar;
      Application.ProcessMessages;
      DoFork;
    end;
    
    procedure TMainForm.BtnClick3(Sender: TObject);
    begin
      TThread.CreateAnonymousThread(
        procedure
        begin
          DoFoo;
          DoBar;
          DoFork;
        end).Start;
    end;

     

    Problem with Application.ProcessMessages is that code that would execute in one block without interruptions, like in first example, can now be interrupted and some other code can start running in the middle of it. For instance you can click same button twice. Or you can close form and destroy it while other code is still running and using it.

     

    Now moving in background thread does not solve those issues, because you can still click the button twice and you can close the form while you running something in the background.  

    But, there are few things to consider here. First, while code with ApplicationProcessMessages can be interrupted at any point, code in background thread will run serially, one line after the other, just like the code that does not call Application.ProcessMessages. It is far easier to follow the logic (and debug) such code.

     

    One of the arguments for Application.ProcessMessages was that it is easy to use, comparing to multithreading. That is true only on the surface, it seems easy and that is why we were all using it. 

    So you have beginner developer writing all kind of poor code in event handlers and application becomes unresponsive, so he is advised to use ApplicationProcessMessages, and he sprinkles his code with those and application might work better (seemingly).  In the reality, he learned nothing, his code is really bad, and sooner or later when some user clicks something unexpected everything will fall apart.

     

    When you have to move code to the background thread, you need to think more about it and you need to isolate it better. Mere process of isolating functionality will make that code better. Now, you can still have developer that will just move the whole thing to the background without doing any of that, but that code will not seemingly work (that rarely happens) and it will not work properly, which will hopefully trigger the developer to ask for help and learn how to do that properly.

     

    10 hours ago, Attila Kovacs said:

    "may respond to user input slowly"

    Yes. Just like a thread "reacts" slowly, when you want to cancel it and it just won't stop right away because it's too busy to check if there was a stop signal.

    There is a difference. If the UI reacts slowly that means when you drag the window and it will not drag smoothly, when you click the button you may not get immediate response, so you will click it again. Background thread does not block the UI so it does not matter how long it takes to cancel the operation. You can write your code in such manner that when action is canceled, user can immediately continue doing something else.

     

    10 hours ago, Attila Kovacs said:

    "but all the calls to Application.ProcessMessages will make that long operation running even longer"

    You are right. 2 cores are more than 1. But no, because we have to move a lot of data between the threads. Many times.

    And this is not something to ignore. Putting a piece of blocking code into a thread just because the GUI, could be rocket science.

    You don't have to move data between threads - data is not contained within threads (unless you specifically create thread local data), you just need to prevent multiple threads changing the same data simultaneously.

     

    • Like 4

  2. 2 hours ago, Attila Kovacs said:

    @Dalija Prasnikar Could you explain the difference between "putting a db task into a thread" (thread) vs. "application.processmessages" regarding to the GUI?

    First, as we all know (I hope) if application cannot process messages, it becomes unresponsive and OS (and user) can kill it, because it may look like it is dead.

     

    Application.ProcessMessages pumps the message queue so the OS can see that application is still alive. There are few problems with that approach.

     

    Most obvious problem is that such code becomes re-entrant. That can cause some nasty side-effects depending on the code you are executing. 

    But main issue is that you are still running slow operation in main thread, and no matter how much you are able to interrupt that execution with calls to Application.ProcessMessages, this will still slow down UI processing and application may respond to user input slowly. Also, this is not just the problem with reacting to input, but all the calls to Application.ProcessMessages will make that long operation running even longer.

     

    Next issue that is often overlooked is that some parts of the long running process may not always execute fast enough. Imagine connecting to some web service and retrieving some very small amount of data. In perfect conditions that may take blink of an eye, but if connection is bad for any reason, this operation can block the main thread for much longer. And Application.ProcessMessages will not help you with that.

     

    Also, for cross-platform development, this is more important because mobile devices will kill non responsive application much faster. On Android you cannot even freely perform network operations in the context of the main thread because OS will thow exception if you try. Also on android Application.ProcessMessages no longer works and can deadlock the application.

    • Like 4

  3. 23 minutes ago, David Heffernan said:
    1. Run in the debugger.
    2. When it hangs, use Run | Program pause to pause execution.
    3. Look at the thread window, and double click the main thread since I guess that is the thread which is hung.
    4. Look at the call stack window which will tell you what the thread is doing that is not completing.

    It seems that everything is running in main thread... so nothing really hands besides application UI.


  4. 20 minutes ago, Fr0sT.Brutal said:

    Simple way is to call Application.ProcessMessages from time to time

    This is bad idea.

    First, Application.ProcessMessages has some global side effects that can bite you in behind when you least expect them. Next, depending on the code, it is possible that some pieces still take too long to keep UI fully responsive.

     

    Using background threads for simple operations is not rocket science and at the end when you take all pros and cons it is not more complicated than using Application.ProcessMessages.

    • Like 6
    • Thanks 1

  5. 34 minutes ago, Mike Torrettinni said:

    I didn't initially test TStringBuilder because I don't have any experience with it and also I remember reading that it was very good solution in early versions of Delphi, then they optimized everything else and it became not so performant in latest versions.

    But if it would be faster or the fastest, I would use it!

    Delphi strings are pretty good as far as performance is concerned, TStringBuilder might have advantage when you need to handle longer strings and where benefits of preallocating buffer will outweigh the cost of the builder allocation, deallocation and try...finally block.

    I use TStringBuilder in few places, where it simplifies code, and I never measured the speed because it was not important in there.

     

    If you want to knock yourself out with micro-optimizations, you should definitely take a look at Knuth-Morris-Pratt algorithm, especially if you are matching same patterns over and over again https://en.wikipedia.org/wiki/Knuth–Morris–Pratt_algorithm

     

    • Thanks 1

  6. 6 hours ago, Mike Torrettinni said:

    Here is description of how my function works:

    1. Get all Positions of all substrings

    2. Sort Positions, so we make replacements from 1..n one by one (if we don't sort and make replacements randomly within a string, it's a mess...)

    3. Loop Positions and make replacements (copy each replacement and parts between replacements into single Result string)

     

    Initial idea that multiple scans are bad for performance is good, but your steps are wrong.

     

    You should scan the string for all substrings in one go, but you should also build new string while you are scanning. Using TStringBuilder or similar pattern with preallocated buffer would be appropriate.

     

    And when I sad scanning string for substrings, don't use Pos function. Scan string one character at the time and match it with patterns you are looking.

    • Thanks 1

  7. You don't need to uninstall 10.3 or older versions. 10.4 can coexist with them.

     

    Installer will probably recognize your existing license. And ask you if you want to use it. If it does not recognize it, they it will ask you for serial number and you will need to go through online activation process.

    • Thanks 1

  8. 2 hours ago, Edwin Yip said:

    As you said, my advise of not accessing a global TEvent variable is to gain flexibility, but not thread-safety - the thread-safety has been provided by TEvent which is a 'sync object'.

     

    So I really don't understand why you said the advise is wrong while you agree on the effects of the advise...

    I am sorry if I misunderstood your point.

     

    You didn't explicitly said why are you suggesting passing TEvent instead of using global access and phrase "Don't forget" can be easily interpreted that if you use global objects directly, code will not work properly. At least that is how I have read it.


  9. 3 hours ago, Edwin Yip said:

    I think this the standard and easy way. But don't forget to pass the TEvent object to each threads, avoid accessing any global vars in anywhere including inside the a thread.

    Not using global vars is good advice, but your particular advice here is wrong for several reasons.

     

    First, accessing global state (and changing it) is always a problem when it comes to thread safety, because one thread can change that state and interfere with the other using that same state. Think of global TFormatSettings variable. Having formatting functions that works directly with global setting is not thread safe because different threads can change settings as they please. On the other hands functions that use format settings passed as parameter are safe. But the crucial thing here is not passing as parameter alone, but what happens when you pass it in this particular case. TFormatSettings is a record and when you pass it as parameter function will get a local copy of the whole record. That is what it makes it safe.

     

    When you pass object instance as parameter, function will not get local copy of the object, just the reference. If the object is not thread safe and does not implement thread safety (synchronization) mechanisms that would allow safe access from multiple threads, then using parameter or global object directly is equally bad, and will not work.

     

    However, when it comes to synchronization objects, including TEvent, their whole purpose is to be shared between multiple threads. And if you need to orchestrate threads on application level, the only way you can do that is through global object. Yes, you can still write code in such manner that it does not access global object directly, but that code will not be "more thread safe", but more flexible and allows you to pass different TEvent instances to different threads that may have different purpose and possible different synchronization events.

     

    Using global locks, events and other synchronization objects is perfectly fine.

     

    • Like 2

  10. 11 hours ago, FredS said:

    You mean while they repeatedly shut down and wipe historic info from the newsgroups and the forum for extended periods?

    NNTP forums were the only ones that were really used. They were not shut down and deleted on a whim, but because of software and database problems. Posts were purged in attempts to stabilize and salvage the forums, but failures keep happening. During that time Embarcadero created new web only forums, but they were never extensively used - I am not going to analyze why.... 

    11 hours ago, FredS said:

    Because I thought it was a perfect split, SO for code stuff and those Newsgroups and Forums for hard to figure out errors and missing documentation.

    Well, now you have Delphi Praxis for that. Old forums as such may be lost, but community is not. Many people are here and that is all that matters.

    • Like 4

  11. 1 hour ago, Attila Kovacs said:

    So you just gave the things an indian name "not receiving too many new features as people would hope so", and telling us that its evolving but only things getting fixed which are part of the IDE, and mentioning "overnight" fixes and "mature" but buggy since XE2. That was a rollercoaster to read.

    There are two separate things here. VCL and VCL Styles. You said that VCL is being abandoned by Embarcadero and that is simply not true as there is a huge difference between "not receiving too many features" and being abandoned.  Also by "not receiving too many features" I definitely didn't want to say it barely received any. There were numerous features introduced in VCL since XE2, some were VCL only, some were both VCL and FMX. 

     

    The part with bugs and IDE and "overnight fixing" is strictly related to VCL Styles. Only introducing styles to IDE exposed how buggy they really are and how much fixing they need. And that amount of fixes cannot be made overnight.

     

    VCL is mature framework. I never said that for VCL Styles. VCL Styles were never mature, they are just feature that was never properly finished in the first place.

     

    I hope this is more clear now.

    • Like 1

  12. To avoid flooding another thread with unrelated posts about VCL quality and bugs, I have opened this topic for discussion about VCL in general and VCL Styles.

     

    First, I would like to respond to comment made by @Attila Kovacs

     

    Quote

    I'm chanting since ages that VCL is practically abandoned by Emba.

     

    VCL is not abandoned, not even close. Maybe it is not receiving too many new features as people would hope so, but it has more to do with its maturity than anything else. FMX (is) was in frenzy development cycle, only because it didn't have the needed features VCL already had, and it still does not have all. So it may have seemed that FMX is getting all the love and attention, but that was not the case.

     

    Many new Windows related features introduced since FMX has come to play, are still VCL only. 

    Keep in mind that IDE is based on VCL, and I don't see that changing in foreseeable future. VCL is evolving and it will continue to evolve. It is not that FMX is new better, improved framework mean to replace VCL for all purposes, it is framework with completely different architecture and it covers different use cases. While some functionality certainly overlaps, and there are (Windows only) applications where both VCL and FMX can be chosen, there are also applications where VCL is far better (and sometimes, even only viable) choice.


    VCL Styles are buggy, they have been buggy since they were introduced in XE2. But, they are now part of the IDE. That means two things. First, IDE is now suffering from some bugs, but it also means that those bugs will get fixed sooner rather than later.

    Unfortunately, not all bugs can be solved overnight, and the more specific, reproducible bug reports there are, the higher are chances that those bugs will get a fix.

    If you have any filed VCL bug reports you might want to share, please do so. 

    • Like 14
    • Thanks 1

  13. 1 hour ago, sjordi said:

    I talk about "responsive" the way webpages are... say your screen is not as wide, then controls clutter on top of each others instead of being next to each others.

    You are describing bad web page (I know there are plenty of those in the wild). This is not how web pages should behave 🙂 Nor any other GUI...

     

    In general, most mobile designs have some kind of scrollable container as root and then you adapt your content to fit the screen width, and what does not fit, you wrap it around. Additionally, you can have some fixed top or bottom bar for navigation. Only the simplest screens with just few controls, can avoid scroll bar.


  14. 12 hours ago, sjordi said:

    What  I don't want is a responsive-like app, behaving like a webpage

    I am afraid that your wishes are not aligned with reality.

     

    Unless you write your application for specific customer, targeting specific devices (screen sizes), your layouts will need to be dynamically adjustable. Like @Rollo62 said, this is mission impossible with zillion devices on the market. 

     

    I think that using different form size layouts will only make things more complicated, than adjusting layout at runtime, even if you need to tweak it through code.

×