Jump to content
ewong

Determining why Delphi App Hangs

Recommended Posts

Hi,

 

I have an application which goes through a dataset (a 13k+ entry table) and grabs info and adds it into a dictionary for

further use.   Due to the length of the table, I had also created an extra form which is basically just a progress bar.

 

When I run the app,  the progress bar's position increases.  The problem is when I click on something else within the form.  The application immediately

hangs (Application Not Responding).   The application is still running though.  After some time, the progress form closes and the data is displayed.

 

I had thought it was a painting issue; but even adding progressform.repaint to the end of the (while not dataset1.eof do) loop, the application hangs.

 

Is there a way to find out what part of the code is hanging or why it's hanging? 

 

Thanks

 

Ed

 

 

Share this post


Link to post

Yes, there is. But without code it is impossible to say for sure.

 

I am guessing that you are doing all that in main thread.

Share this post


Link to post
57 minutes ago, Dalija Prasnikar said:

Yes, there is. But without code it is impossible to say for sure.

 

I am guessing that you are doing all that in main thread.

That I believe I am since I'm not using threads or anything.   I think I'll try using threads and see how things go.

 

Thanks for the idea!

 

Edmund

Share this post


Link to post
23 minutes ago, Fr0sT.Brutal said:

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

Thanks for that suggestion.  I'll keep that in mind for the smaller apps.

 

Edmund

Share this post


Link to post
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

Share this post


Link to post

Do not try update ProgressBar position for every single entry, let it update in steps. ProcessMessages is really a bad Idea!

Share this post


Link to post

Am i wrong, but i seem to remember that the progress bar actually calls Application.ProcessMessages.

IMHO that could be your problem. Messages starts to pile up because of something and then when that is finished all those messages gets processed and it looks like a "release".

Anyways, show us the code. You could do an MVP using a TClientDataSet perhaps.

Share this post


Link to post
Posted (edited)

poor man's responsive GUI

 

 

var
   FOldMessageEvent: TMessageEvent;


FOldMessageEvent := Application.OnMessage;
Application.OnMessage := MyOnMessage;
try
  // Do your stuff here and call repetitively Application.ProcessMessages;
finally
  Application.OnMessage := FOldMessageEvent;
end;

procedure TfrmXY.MyOnMessage(var Msg: TMsg; var Handled: boolean);
begin
  if (Msg.hwnd = btnStart.Handle) and (Msg.Message = WM_MOUSELEAVE) then
  else if Msg.hwnd = btnAbort.Handle then // if you have an abort button
  else
    case Msg.Message of
      WM_PAINT, WM_TIMER: // handle messages
        ;
    else
      Handled := True;
    end;
end;

 

Edited by Attila Kovacs

Share this post


Link to post
5 hours ago, ewong said:

Is there a way to find out what part of the code is hanging or why it's hanging? 

  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.
  • Like 3

Share this post


Link to post
2 hours ago, Dalija Prasnikar said:

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.

This is simple and good enough idea for the app described. Side effects are insignificant in single-threaded app (possibility of user input during processing could be easily blocked). Using bg threads for DB actions is getting a little closer to rocket science than App.PrMsg and could seem an overkill for simple app or junior dev.

Share this post


Link to post
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.

Share this post


Link to post
Quote

When I run the app,  the progress bar's position increases.  The problem is when I click on something else within the form.  The application immediately

hangs (Application Not Responding).   The application is still running though.  After some time, the progress form closes and the data is displayed.

 

Disable the controls

When data is loaded have future event enable controls.

Rather than a progress bar have windows 10 olympic ring showing until future event happens.

 

Share this post


Link to post
2 hours ago, Attila Kovacs said:

poor man's responsive GUI


var
   FOldMessageEvent: TMessageEvent;

FOldMessageEvent := Application.OnMessage;
Application.OnMessage := MyOnMessage;
try
  // Do your stuff here
finally
  Application.OnMessage := FOldMessageEvent;
end;

 

 

I don't think you understand how the message queue works...

How are messages supposed to arrive through Application.OnMessage if the message queue isn't being pumped? And if it is being pumped then your code is unnecessary because the messages are already being dispatched and processed. In short: Your code does nothing that isn't already being done.

  • Thanks 1

Share this post


Link to post
3 hours ago, Dany Marmur said:

Am i wrong, but i seem to remember that the progress bar actually calls Application.ProcessMessages. 

Yes. You are wrong.

It processes WM_PAINT messages (which is why it's updating) but leave everything else alone.

  • Like 1

Share this post


Link to post
8 hours ago, ewong said:

When I run the app,  the progress bar's position increases.  The problem is when I click on something else within the form.  The application immediately

hangs (Application Not Responding).   The application is still running though.  After some time, the progress form closes and the data is displayed.

 

I had thought it was a painting issue; but even adding progressform.repaint to the end of the (while not dataset1.eof do) loop, the application hangs.

First of all the application isn't hanging. It's just not processing messages while it's working.

 

When you click on the form Windows detects that the application hasn't pumped the message queue for a while and assumes this is because the application is stuck in an endless loop somewhere. In your case that's a wrong conclusion because eventually your task finishes and everything is good again.

 

The simple work around is to pump the message queue inside your loop - just don't use Application.ProcessMessages. I believe have previously posted some code here that can be used inside a loop to allow the user to interact with a progress dialog (e.g. move it, push an abort button, etc.) without the pitfalls of Application.ProcessMessages but if you can't find it you can at least pump the queue for WM_NULL messages. I think these are what Windows use to detect a hung application:

var Msg: TMessage;
while PeekMessage(0, Msg, WM_NULL, WM_NULL, PM_REMOVE) do
begin
  if (Msg.message = WM_QUIT) then
    PostQuitMessage(Msg.wParam);
end;

 

8 hours ago, ewong said:

Is there a way to find out what part of the code is hanging or why it's hanging?  

If you can reproduce while running in the debugger then just press the Pause button in the debugger and examine the call stack.

At run time you can use something like madExcept's freeze detection. It uses the same technique as Windows to detect a hung application and produces a nice call stack when it happens (after prompting the user).

Share this post


Link to post
11 hours ago, ewong said:

I have an application which goes through a dataset (a 13k+ entry table) and grabs info and adds it into a dictionary for

further use.   Due to the length of the table, I had also created an extra form which is basically just a progress bar.

Isn't it classic block

while not DS.Eof do
begin
  ..copy values...
  FormProgress.PrBar.Stepit;
  DS.Next;
end;

? If so, there's nothing that hangs in your app.

Share this post


Link to post
Guest
Posted (edited)

why all stop on main thread????

 

It's quite simple!!!

 

remember: a Form always is onto a looping infinite... look on sources, where, the msg is 'catch', and executed... but the looping still been executed until close a form....

for that, ProcessMessage exist, basically.

 

i remember when I used Clipper summer85 :classic_cheerleader:

 

sorry my english

 

hug

Edited by Guest

Share this post


Link to post
4 minutes ago, emailx45 said:

why all stop on main thread????

 

application repeat 

 

      db-task while not dataset.eof do

       begin

           // main loop blocked    

          dataset.next;

       end;

 

 form2.showmodal ->

      modal form repeat 

          Application.ProcessMessages; <- modal form workaround, bites as hell

      until ModalResult <> 0

 

  Application.ProcessMessages;

until terminate

 

 

 

 

 

Share this post


Link to post
Guest
Posted (edited)

I didnt a question! 😁

 

I showed a fact! :classic_biggrin:

 

hmmmmm... it's so hard somebody "understand:classic_cool:

 

hug

Edited by Guest

Share this post


Link to post
Posted (edited)

well, you have to learn foreign languages then, or look for a native forum, you see me? friend 🙂 :classic_cheerleader:

Edited by Attila Kovacs

Share this post


Link to post
Guest

no no.

 

hug

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×