Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: CBXE8 - Application->ProcessMessages() not working in recursive path scan ?


This question is answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 4 - Last Post: Oct 13, 2015 5:41 PM Last Post By: GAI CHEW KAI
GAI CHEW KAI

Posts: 117
Registered: 7/25/14
CBXE8 - Application->ProcessMessages() not working in recursive path scan ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 12, 2015 6:21 PM
Embarcadero® C++Builder XE8 Version 22.0.19027.8951 and Indy 10.
Window 10 Pro x64, Version 10.0.10240
Android 4.1.2

QUESTIONS

1. I have a recursive path enumerator, while scanning path, Application->ProcessMessages() is called on each path scanning recursive loop within, via function call method:

class cPathFinder
{
cPathFinder () { m_bAbort = false; );
....
bool m_bAbort;
int (*fp) (__in char16_t* pc16Path, __in char16_t* pc16File, __in int iFolderCnt, __in int iFileCnt, __in int iCLSID );
....
};

int cPathFinder::f_iOnScan ( ... )
{
...
while( !m_bAbort )
{
....
(*fp)( ... ); // Call to a Function "f_iOnPathFinderMsgProc()" declared under Form1 source.
....
f_iOnScan( ... ); // if detected folder, we do a re-cursive call.
....
};
...
return 0;
}

// fp() is assigned with f_iOnPathFinderMsgProc(); under Form1 source:
cPathFolder g_oPF;
g_oPF.fp = &f_iOnPathFinderMsgProc;

int f_iOnPathFinderMsgProc ( ... )
{
Application->ProcessMessages();

return OS_OK;
}

// Second Application->ProcessMessages() under a timer as well.
// I cannot put a Third one into a Thread because it caused exception error.
void __fastcall TForm1::tmOnTimer (TObject* Sender)
{
....
Application->ProcessMessages();
....
}

// An ABORT button is put on Form1's tabsheet, to set m_bAbort if needed.
void __fastcall TfMain::btnAbortOnClick (TObject* Sender)
{
g_oPF.m_bAbort = true;
}


When there is deep path scanning via f_iOnScan(), the btnAbortOnClick() is not functioning when tapped and just hang there until the scanning is finished then only it begins to respond.

Please advise.

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: CBXE8 - Application->ProcessMessages() not working in recursive pathscan ? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 12, 2015 7:23 PM   in response to: GAI CHEW KAI in response to: GAI CHEW KAI
GAI wrote:

I have a recursive path enumerator, while scanning path,
Application->ProcessMessages() is called on each path
scanning recursive loop within, via function call method:

Anytime you have to resort to using ProcessMessages(), it is a hack covering
up bad design, you are likely doing things wrong to begin with. Especially
since you also have nested calls to Application->ProcessMessages() (why are
you calling it in a timer anyway? It does not belong there). And DO NOT
call ProcessMessages() inside of a worker thread! It can only be called
safely in the main UI thread.

You really need to re-write this code to stop blocking the main UI thread
at all. This is especially important on Android. Its main UI thread is
very sensitive to blockages. If you block the main UI thread for any noticable
amount of time, Android is likely to just kill your app immediately because
it is not being responsive enough. Windows is a little more forgiving (but
not much) about UI blockages - it will prompt the user before killing your
app.

So, you should either:

1. move the scanning code as-is to its own worker thread and get it out of
the main UI thread completely. Notify the main UI thread only when there
are updates needed, such as for display in the UI.

2. re-write the scan to work asynchronously. Do a small amount of scanning,
then post a message back to yourself, or start a short timer, and then return
control to the main message loop. When the message/timer is triggered, do
a little more scanning, and then post a message/timer to yourself. And so
on, until the scan is finished.

Personally, I would go with a worker thread. It is easier to code and manage.

--
Remy Lebeau (TeamB)
GAI CHEW KAI

Posts: 117
Registered: 7/25/14
Re: CBXE8 - Application->ProcessMessages() not working in recursive pathscan ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 13, 2015 5:08 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
>...Application->ProcessMessages() (why are you calling it in a timer anyway? It does not belong there)
- I put the UI routine ( file/folder item list created dynamically routine ) under the Timer routine.
- within the UI routine loops, there is call to ProcessMessages() for each file/folder listing item dynamically created and displayed on Form1.
- with this approach, at least is able to capture user inputs ( eg. an ABORT button signal to quit the deep path scanning which work eventually ).

> ...do not call ProcessMessages() inside of a worker thread! It can only be called safely in the main UI thread.
- is TForm1 the main UI thread ?
- is ProcessMessages() safe to be placed under OnTimer() ?
- are both TIdUDPClient and TIdTCPClient considered can be called safely in the main UI thread and worker thread ? I have physical tested both environments, the result is ok.

> You really need to re-write this code to stop blocking the main UI thread at all.
- Apologizing, is my mistake that forgotten to quit from the UI routine once ABORT signal is detected.

> 1. move the scanning code as-is to its own worker thread
- Yes, eventually I put the NON-UI scanning routine in a worker thread, is working ok.

and get it out of the main UI thread completely.
- After the NON-UI scanning routine completed in the worker thread, its cached file/folder information stored in a memory queue is later used by UI routine in Timer routine via a global notification flag. eg. g_bScanPathCompleted = true.

> 2. re-write the scan to work asynchronously.
- Please advise with some async methods.

> Personally, I would go with a worker thread. It is easier to code and manage.
- is true, but in my case there is a need to dynamically create file/folder UI listing, eventually I placed the UI routine in Timer routine, you have any suggestion how is this UI routine should be notified within main UI thread if not under Timer routine ?

Thanks Remy for the feedback again, I really appreciated it.

Please advise.

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: CBXE8 - Application->ProcessMessages() not working in recursivepathscan ? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 13, 2015 5:35 PM   in response to: GAI CHEW KAI in response to: GAI CHEW KAI
GAI wrote:

- I put the *UI routine ( file/folder item list created dynamically
routine )* under the Timer routine.

- within the UI routine loops, there is call to ProcessMessages()
for each *file/folder listing item dynamically created and displayed
on Form1*.

- with this approach, at least is able to capture user inputs ( eg. an
ABORT button signal to quit the deep path scanning which work
eventually ).

That is not a good design choice. Move the list creation to a worker thread,
and then notify the main thread when you have items to display visually in
the UI.

- is TForm1 the main UI thread ?

TForm1 runs in the context of the main thread. It is not the main thread
itself.

- is ProcessMessages() safe to be placed under OnTimer() ?

If the timer is running in the context of the main thread, yes. But I would
not advise doing it. You can cause reentry issues by pumping the message
queue manually. Better to break up your code so you are not doing so much
work in one event handler to begin with.

- are both TIdUDPClient and TIdTCPClient considered can be called
safely in the main UI thread and worker thread ?

Not by both threads at the same time. But in general, yes. They operate
in whatever thread context is calling into them.

- Apologizing, is my mistake that forgotten to quit from the *UI
routine* once ABORT signal is detected.

No. It is that you are doing too much work in one event, and it is blocking
the event handler from returning control back to the message loop in a timely
manner. Any time you have to do any work that takes more than a few seconds
at most, causing a noticable delay in UI rendering, it belongs in a worker
thread.

and get it out of the main UI thread completely. - After the
NON-UI scanning routine completed in the worker thread, its *cached
file/folder information stored in a memory queue* is later used by *UI
routine* in Timer routine via a global notification flag. eg.
g_bScanPathCompleted = true.

I would use the TThread.Queue() method or the TThread.OnTerminate event instead
to notify the main thread when the scan is finished.

--
Remy Lebeau (TeamB)
GAI CHEW KAI

Posts: 117
Registered: 7/25/14
Re: CBXE8 - Application->ProcessMessages() not working in recursivepathscan ? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 13, 2015 5:41 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Thank you, problem solved.
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02