views:

227

answers:

4

Hello

i have a simple program that sorts a text file according to length of words per line this program works without problems in my xp based old machine now i run this program on my new win7/intel core i5 machine, it freezes whole system and back normal after it finishes it's work.

i'v invastigated the code and found the line causing the freeze

it was this specific line...

caption := IntToStr(i) + '..' + IntTostr(ii);

i'v changed it to

 caption :=   IntTostr(ii);  //slow rate change

and there is no freeze

and then i'v changed it to

caption :=   IntTostr(i);  //fast rate change

and it freeze again

my procedure code is

 var tword : widestring;
      i,ii,li : integer;
 begin   
     tntlistbox1.items.LoadFromFile('d:\new folder\ch.txt');
     tntlistbox2.items.LoadFromFile('d:\new folder\uy.txt');
     For ii := 15 Downto 1 Do //slow change
      Begin
        For I := 0 To TntListBox1.items.Count - 1 Do //very fast change
        Begin     
          caption := IntToStr(i) + '..' + IntTostr(ii); //problemetic line               
          tword := TntListBox1.items[i];
          LI := Length(tword);
          If lI = ii Then
          Begin             
            tntlistbox3.items.Add(Trim(tntlistbox1.Items[i]));
            tntlistbox4.items.Add(Trim(tntlistbox2.Items[i]));
          End;
        End;
      End;
    end;

any idea why ? and how to fix it? i use delphi 2007/win32

+8  A: 

Is this happening inside an event handler on a form? I'm going to guess taht it is. In that case, "Caption" is in the scope of the form. The form's caption text isn't managed by the VCL, but by Windows, and if you're sending a new WM_SETTEXT message on every iteration of the loop.

A thorough explanation of why this is doing what it's doing would require knowledge of Windows internals that I don't have, but if I were to take a guess, I'd say it's something like this:

Every time you send that WM_SETTEXT message with a new caption, Windows checks to make sure it's not identical to the existing caption. If it is, it can exit immediately. That's why the infrequent change (the one that only uses ii) doesn't slow your system down. But if it does change on every iteration, then Windows has to perform some sort of task switch in order to change it.

As for why that would bog down the entire system under a Vista kernel (including Win7) but not XP, that's completely outside my area of expertise. But if you're trying to do this as some sort of progress indicator, there are better ways, especially if this loop is as tight as it looks.

The best way to handle progress updates in a tight loop is to count iterations and only fire once every X times. (100 or 1000 can be good values for X, depending on how many times it's running and how fast the whole thing takes.) This is basically what the ii only option does. You could also try putting a Progress Bar on the form to measure progress instead of doing it through the form's caption.

Mason Wheeler
+1 likely what is going wrong here. We recently fixed a bug in our system where we were sending more messages than the message buffer could handle, also resulting in a seemingly frozen (xp) system.
Lieven
thanks Mason for your suggestion, i'll try to use progress bar instead .and yes it is a TForm1.Button1Click() handler.
avar
A: 

Try to insert this line after your 'caption' statement. This line forces to refresh your caption before continue execution.

Application.ProcessMessages;
Vincent
i already tried that, no use.
avar
This will make things worse, not better. The problem is updating too often.
Alexander
There is no refresh problem and adding Application.ProcessMessages won't solve anything here.
The_Fox
This could be useful to enable the caption to paint, but not if you're going to do it 35,000 times. Would be useful if the caption change (and processmessages - and then, only if needed) were to occur every 100 or 1000 items. Can be easily done with a mod test.
Chris Thornton
+2  A: 

Changing a Form's caption releases a whole bunch of actions - especially under Vista and Win7 with Aero active.

A quick try would be using a TLabel instead for displaying progress. Something like

Label1.caption := IntToStr(i) + '..' + IntTostr(ii); //problemetic line               
Label1.Refresh; // or Repaint

should do the trick unless your label is transparent or on a glass area.

It would probably be best to follow Mason Wheeler's advice and use a progressbar. As the overall number of iterations is 15*TntListBox1.items.Count you can calculate the progress value quite easily.

Uwe Raabe
i'll try the code again with Aero turned off ..
avar
+1  A: 

First: you forget tntlistbox3.items.BeginUpdate/tntlistbox3.items.EndUpdate calls (same for tntlistbox4).

Second: Why does my program run faster if I click and hold the caption bar?

Solution (example):

const
  UpdateInterval = 500; // half a second
var 
  ...
  LastUpdate: Cardinal;
begin   
  ... 
  LastUpdate := GetTickCount + 100000; // forces first update
  For ii := 15 Downto 1 Do //slow change
  Begin
    For I := 0 To TntListBox1.items.Count - 1 Do //very fast change
    Begin     
      if (GetTickCount > (LastUpdate + UpdateInterval)) or
         (GetTickCount < LastUpdate) then
        caption := IntToStr(i) + '..' + IntTostr(ii); //problemetic line               
      ...
    end;
  end;
Alexander