Delphi: frozen form - multithreading

There are 2 forms.
Form2 isn't auto-created.
Form2:=TForm2.Create(Application);
Form2.Show;
If to do Sleep(10000); inside any forms then another one will be frozen. How to prevent this behavior?
My problem: a big text file (3 Mb) is continuously assigned (Lines.Assign) into a text editor, so a form is frozen.
Can I use another unfrozen form (not modal) to show a progress bar (a style is pbstMarquee)?

All GUI code should be run from the main thread, and it looks like you are following that rule.
If you call Sleep then the calling thread will not execute code until the timeout elapses. If you call Sleep from the main thread, then the message queue will not be pumped until the timeout elapses. Hence the entire app appears frozen.
Why does calling Sleep from one form affect another form? Because all GUI components are served from the single message queue of the main thread. Once you stop pumping that queue, all GUI components stop receiving queued messages like WM_PAINT, WM_KEYDOWN etc.
As I understand it your problem is that your application appears hung when you are loading a 3MB text file into an edit control. That size of file doesn't sound very large to me and one obvious solution would be to find an edit control that performs the load better. For example I'm pretty sure that Notepad, Notepad++ etc. do not take steps like showing progress when loading such files. I rather suspect that those apps don't pump the queue when loading files but you just don't notice because of the short time taken.
What you don't want to happen is for you to pump your queue to keep your GUI responsive and in turn allow the user to start loading another file whilst the first one is still loading. You need to disable your UI whilst processing a load operation. A modal progress dialog is one way to do that.
If you can't switch to a better performing control, you could show a modal progress dialog and use a background thread like this. The background thread would have load the file in small chunks, say into a string list. After each chunk of the file was ready it would then call Synchronize and get the main thread to add the contents of the string list to the edit control, and then clear the string list. The thread would then continue and load the next chunk. Adding to the edit control in small chunks would allow you to keep the message queue serviced.
You could show progress in a status bar rather than a modal dialog which would be less intrusive. But just remember to disable any UI that would cause re-entrant execution.

Better load your file in a separate thread. Or you will have to create your second form in a plain WinAPI, because VCL doesn't support multithreading.

Related

How to programmatically do the same as back button does?

I have an app originated from "DirectX and XAML" project template. The main processing is made in a worker thread, and when some input event occures on main thread (like touch or back button pressing), I save it in a special storage and then process on the worker thread's game tick.
Due to that deferred nature of input handling, I cannot immediately decide should back button pressing be consumed or passed through. And I always mark it as consumed.
But if worker thread later decides that back button should be handled naturally (it means exiting the app), how do I achieve this? I know about Application.Current.Terminate();, but I hope there should be more elegant way to programmatically "press back button".
I suppose you would want to use the NavigationService
if (NavigationService.CanGoBack)
NavigationService.GoBack();

Progress bar control......between two dialog

My application is based on serial communication.
It has main dialog window, from this we can select three options pump,crind and kiosk.
When i choose any one say pump, then small dialog is called (CommonResponse)with progress bar and getting time of pump from command files.This small window is on separate thread created as worker thred.
Now i want this small window with progress bar is on main thread but in background serial communication should be going on......How to do and steps for doing this?
One option for doing this is instead of progress bar, serial communication is on separate thread.But it is very time consuming process now because all things are ready only this part we want to change....
Thank you in advnce!!!
Just pass a handle to your main thread window to the background thread.
Use PostMessaage to send a private message that informs the main thread about the progress. The main thread can decode it and set the embedded progress bar to the value you want and need.

How can I perform actions while waiting for vertical sync?

I want to be able to load/download a bunch of resources and notify the user of the file that's currently being loaded, but I can't just draw a frame after each file starts loading because v-sync will wait until it can draw a frame before it continues (bottle-necking the loads to less than 60/second).
Is there a way to check whether the device is ready to draw or not (without hacky "has 1/60th of a second passed yet?), so I can perform actions until it's ready? I don't mind if the notification skips over files that finished before it's ready to draw, but I want to maximize the speed of the loads while still being able to notify the user.
Also, I'd like to avoid disabling v-sync even temporarily because I don't want to cause a graphic card crippling 300FPS rate if the computer loads really quickly.
You don't specify which version of Direct3D you're using. With D3D9 you can pass D3DPRESENT_DONOTWAIT to your Present() call and it will return D3DERR_WASSTILLDRAWING if the hardware is busy processing or waiting for a vertical sync interval. This means if you have vsync enabled, in your main loop you can just call Present with the DONOTWAIT flag whenever you've loaded a file and load another if it returns WASSTILLDRAWING.
Note that you need to get the swap chain and call Present() on the swap chain rather than calling Present() directly on the device to be able to pass this flag to present, or you can set it in the D3DPRESENT_PARAMETERS structure when you create the device or create an IDirect3DDevice9Ex instead of an IDirect3DDevice9 device and call PresentEx() instead of Present().
This doesn't solve the problem of files that take longer than a frame to load however - your frame rate will drop if you have a file that takes a long time to process. A better solution to this problem in my opinion would be to move as much of your IO as possible to another thread (in D3D9 you will still have to create D3D resources on your main thread however) and just pass the name of the file that's currently being processed to your main / render thread to display each time you present a frame.

Window freezes if there are many records in ListView which added from threads

My program do the "heavy" task (searching files and finding a signature) on a separated thread. Every task uses PostMessage to call a procedure for adding a record into a ListView.
The problem is when ListView (often) displays many records, my window will freeze. It seems my program is screaming to request Application.ProcessMessages. Only the Progressbar is still moving. After the operation has finished, everything back to normal.
If I remove the operation for adding record, the operation of my program will run smoothly.
Do you have any idea?
We once hit the limit of how many messages can be posted to the message queue. Most likely you are hitting this limit as well.
From MSDN
There is a limit of 10,000 posted
messages per message queue. This limit
should be sufficiently large. If your
application exceeds the limit, it
should be redesigned to avoid
consuming so many system resources.
From The Best Synchronization is No Synchronization
The problem with PostMessage to the main GUI thread is that you can
"saturate" the main GUI message pump,
and interfere with WM_TIMER and
WM_PAINT messages (these messages are
only dispatched if the message queue
is empty, and PostMessage means that
the queue might never be empty. In
addition, there is a nominal limit of
10,000 messages in the input queue;
after that, PostMessage will discard
the message and return FALSE. In
addition, even if the 10,000 limit is
not hit, even a few hundred messages
can mean that the user sees poor
response to keyboard and mouse input,
an unacceptable situation.
If you work with many items, it might be worth to change the overall structure of your program.
Instead of filling the list view, try filling some other data structure and then make another thread make the windows updates and use SendMessage. That way your worker threads are not stalled and you don't flood your message queue. On the other hand this would require a lot more synchronizing between the threads.
Another way would be to use some control with virtual items, such as VirtualTreeview (which can be configured to behave like a list view) That way you can fill your backing data structure and the control asks for the data as soon as an item is scrolled into view. Because even with millions of items, only a few are visible at a time, this might give you a huge boost in speed, because filling the control now is only a matter of setting the total number of items.
You should consider using a virtual grid control, like the ExGridView from roman mochalov, or Mike Lishke's very popular Virtual Tree View (Delphi Gems). When new content arrives, merely set a flag, and then decide how often you want to refresh the screen, and refresh asynchronously, but not once per new item that comes in.
One refresh per 200 mSec will be all most users can stand to see, anyways.

Which is the correct way to wait for a Thread.finalization and keep my application responsive

Actually i am using this code and works ok, but i 'am wondering if is the correct way.
while WaitForSingleObject(MyThread.Handle, 0) = WAIT_TIMEOUT do
Application.ProcessMessages;
ShowMessage('i am done');
The VCL TThread class has its own WaitFor() method that pumps the main message queue internally when called within the main thread context:
MyThread.WaitFor;
ShowMessage('i am done');
Calling Application.ProcessMessages is generally considered a code smell. Let your main thread idle if it's got nothing to do.
If you ran a company and needed one of your workers to run to the store and grab some much-needed supplies, would you then pace by the door until he got back, or would you prefer to sit in your office and rest and wait for him, and find out that the supplies are here because you hear him walk through the door? Either way, he'll take the same amount of time, but the first way's gonna wear your legs out.
Similarly, instead of having your UI watch the thread, have the thread report back to the UI. One way to do this is to have the thread use PostMessage to send a custom message to the form that launched it once it's finished, and put a message handler on the form to respond to it.
It looks correct (if correct means it do the work). What I would change is to wait for a bit more time (50ms looks good to maintain the application responsive) while not eating CPU.
while WaitForSingleObject(MyThread.Handle, 50) = WAIT_TIMEOUT do
Application.ProcessMessages;
ShowMessage('i am done');
Sure there are other ways to do it... <joke>but I usually apply one of the main engineering principles:
if it works, don't touch it!</joke>
I agree with Mason Wheeler's remark, the main thread is best left to do its job, but I would suggest using the OnTerminate event on the thread. It is more 'Delphi natural' and the internal logic does the PostMessage bit for you. Since TThread is not a component, you can't view it in the object inspector and have to write and attach an event handler yourself. It gets called (in the main thread!) after the thread has completed/terminated.
While it looks okay, like jachguate I would use a bigger time-out value than 0 too. If you use WaitForSingleObject(MyThread.Handle, 100) then the main thread will wait a bit longer, thus eating up less CPU cycles.
A better solution would be the use of messages, though. Your application starts the thread and then puts all controls in disabled mode. The thread then executes and when it's finished, use SendMessage or PostMessage to the main window to notify it that the thread is done again. Then your application will just enable every control (and whatever else) again. This has as advantage that you keep the "natural" messageloop for the application alive, instead of running your own messageloop with this solution.Unfortunately, the message-method has one drawback: if the thread crashes then no message will be sent back, so a backup plan would be practical. For example, by adding a timer control to your mainform which checks every second if the thread is still alive. If not, it too would just activate the form again, disabling itself again.

Resources