I have a backup process copying a lot of files (CopyFileEx) and every few minutes, windows seems to need a break, probably paging-out or clearing buffers or something. During this time, the main form blinks and displays "Not responding" in the main Caption.
After a few seconds it blinks again, the message has gone and all is well with the World and the process continues.
Is there some way I can stop the blink and message?
"Not Responding" has a very specific meaning: The application's UI thread is not continuing to pump messages. The reason Windows calls this "Not Responding" is because the message pump is what sends user input to the application for your code to respond to. Once you understand this, the way to keep the application responsive is obvious: don't run long, blocking operations in the UI thread. Actually implementing that can be tricky, for two reasons.
First, feedback: If you're doing a long operation in a separate thread, you want it to report back to the user on its progress, which can only be done in the UI thread. So you need to use TThread.Synchronize or TThread.Queue or something similar (shameless self-promotion) to post back UI updates to your main thread.
Second, if you have a "copy everything" button in the UI, and it takes a minute to run, and it's running on a different thread but you're keeping the main thread responsive, what's stopping the user from clicking the "copy everything" button again before the task is complete? This may or may not be a valid operation according to your program design, but it it isn't, it can cause problems. Make sure that, if this can be a problem, that your design compensates for it, for example by disabling the button after you click it and re-enabling it after it completes.
Finally, if you're going to do anything complex at all with multithreading, I'd highly recommend you take a good look at OmniThreadLibrary... except that the tag says you're using Delphi 5, which can't run OTL. You really ought to take a look at updating.
Related
Is there a way to know when an iOS app becomes responsive to user interaction? For example, a user taps a button and the app performs work, this work may dispatch other work asynchronously to the main thread. In hopes of using it as a performance metric, I want to know the precise moment at which the app is again able to process touch events in a responsive manner. With this I would want data like "On average, the app becomes responsive 55ms after a user interaction".
Currently, immediately after a user interaction, I watch the main queue and have a heuristic for submitting samples to it in order to estimate responsiveness based on the main queue's responsiveness, with the assumption that the main queue's responsiveness directly correlates with the apps' responsiveness. The sampling only occurs until the queue is again consistently responsive for some time again (ex. 100ms). Is there any downside to this method? Is there any other method I could/should be using to do this?
Using MetricKit to watch for Hang Time is not an option as I cannot those results to a specific interaction (i.e. knowing how different interactions affect hang time).
You said:
For example, a user taps a button and the app performs work. I want to know the precise moment at which the app is again able to process touch events in a responsive manner.
The main thread should never be blocked. It should always be responsive. (You can disable the UI if your app requires that, but never block the main thread, regardless.)
So, with that in mind, if you are starting some process that takes a little time, you should:
If you want the app to let the user know that a time consuming process is about to start, add that chrome to the UI (e.g. UIActivityIndicatorView, aka a “spinner”, or whatever);
Start that task, asynchronously, on a background queue (so that it does not block the main thread);
Give that task a “completion handler” closure that it will call when the background work is done;
In that completion handler, the caller can supply the code to remove any chrome added in the first step, above.
In short, rather than worrying about “how does the app know when the main thread is free again”, you should focus on eliminating anything that would ever block the main thread in the first place. See Understand and eliminate hangs from your app.
Why is it the responsibility of the programmer to call UI related methods on the main thread with:
DispatchQueue.main.async {}
Theoretically, couldn’t this be left up to the compiler or some other agent to determine?
The actual answer is developer inertia and grandfathering.
The Cocoa UI API is huge—nay, gigantic. It has also been in continuous development since the 1990's.
Back when I was a youth and there were no multi-core, 64-bit, anything, 99.999% of all applications ran on the main thread. Period. (The original Mac OS, pre-OS X, didn't even have threads.)
Later, a few specialized tasks could be run on background threads, but largely apps still ran on the main thread.
Fast forward to today where it's trivial to dispatch thousands of tasks for background execution and CPUs can run 30 or more current threads, it's easy to say "hey, why doesn't the compiler/API/OS handle this main-thread thing for me?" But what's nigh on impossible is re-engineering four decades of Cocoa code and apps to make that work.
There are—I'm going to say—hundreds of millions of lines of code that all assume UI calls are executing concurrently on the main thread. As others have pointed out, there is no cleaver switch or pre-processor that's going to undo all of those assumptions, fix all of those potential deadlocks, etc.
(Heck, if the compiler could figure this kind of stuff out we wouldn't even have to write multi-threaded code; you'd just let the compiler slice up your code so it runs concurrently.)
Finally, such a change just isn't worth the effort. I do Cocoa development full time and the number of times I have to deal with the "update control from a background thread problem" occurs, at most, once a week or so. There's no development cost-benefit analysis that's going to dedicate a million man-hours to solving a problem that already has a straight forward solution.
Now if you were developing a new, modern, UI API from scratch, you'd simply make the entire UI framework thread safe and whole question goes away. And maybe Apple has a brand new, redesigned-from-the-ground-up, UI framework in a lab somewhere that does that. But that's the only way I see something like this happening.
You would be substituting one kind of frustration for another.
Suppose that all UI-related methods that require invocation on the main thread did so by:
using DispatchQueue.main.async: You would be hiding asynchronous behaviour, with no obvious way to "follow up" on the result. Code like this would now fail:
label.text = "new value"
assert(label.text == "new value")
You would have thought that the property text just harmlessly assigned some value. In fact, it enqueued a work item to asynchronously execute on the main thread. In doing so, you've broken the expectation that your system has reached its desired state by the time you've completed that line.
using DispatchQueue.main.sync: You would be hiding a potential for deadlock. Synchronous code on the main queue can be very dangerous, because it's easy to unintentionally block (on the main thread) yourself waiting for such work, causing deadlock.
I think one way this could have been achieved is by having a hidden thread dedicated to UI. All UI-related APIs would switch to that thread to do their work. Though I don't know how expensive that would be (each switch to that thread is probably no faster than waiting on a lock), and I could imagine there's lots of "fun" ways that'll get you to write deadlocking code.
Only on rare instances would the UI call anything in the main thread, except for user login timeouts for security. Most UI related methods for any particular window are called within the thread that was started when the window was initialized.
I would rather manage my UI calls instead of the compiler because as a developer, I want control and do not want to rely on third party 'black boxes'.
check https://developer.apple.com/documentation/code_diagnostics/main_thread_checker
and UPDATE UI FROM MAIN THREAD ONLY!!!
I would like to know what's difference between them, I am trying to update something in the UI thus I must do it using the main thread but not sure which of them I should use to accomplish what I want.
Thanks
"User initiated" means the user directly requested this operation, and is likely waiting, but the UI itself is not desperate for a result. "Fetch new tweets because the user performed pull-to-refresh" or "recalculate the tip." These things need to happen quickly, but not immediately. Once the computation is completed, you probably won't ask for it again immediately.
"User interactive" means the user is directly interacting with the result of this operation in real time. The UI needs a result right now or lagging will occur. You will probably be requesting this operation quickly and repeatedly. This is the highest priority.
For full details on these classes, see "Building Responsive and Efficient Apps with GCD."
The app I am working on fetches a bunch of different newsfeeds when it first starts up and updates any expired ones. While this is happening the interface often freezes up and you can't click anything. The actual network calls are being done on a separate thread, but the database operations are being done on the main thread. Would this cause the interface to freeze?
I have been told that I need to make it to where only two feeds to update are inserted into the network operation queue at a time so that it won't try all of them at once, but it's already set up to only do so many network calls at once. I don't understand how having less things in a queue at a time would cause it to go faster if they're just going to be put in there sequentially anyways. Please correct me if I am wrong, I'm still pretty new to this.
Any kind of help regarding what could cause the UI to freeze up during startup like this would be much appreciated!
It is always a good idea to move time consuming operation away from the main thread.
Fortunately it is pretty simple to do on iOS. If the time-consuming task is fairly simple you could consider using performSelectorInBackground
e.g:
[self performSelectorInBackground:#selector(myFunction:)
withObject:myParam];
It is however important to remberber, that you must not access the GUI from the background thread. To get objects back to the main thread use performSelectorOnMainThread
e.g:
[self performSelectorOnMainThread:#selector(myFunction:) myParamwaitUntilDone:YES];
Try applying this strategy to your database calls. Depending on your scenario you might want to wrap it up in a NSOperation or use a Thread when the cause of the freeze is found.
I coding a service application that have two threads.
First thread, show a form with label.
Second thread, query ADO.
First thread always freezing with Hourglass cursor and no label caption.
Please help.
If you're trying to show a form from within a thread that is not the main thread, then you will run into strange things like this. The most notable of which is that if the form and label are created in the non-main thread, then you don't have a message loop to process the messages. If the form was created in the main thread, but you're attempting to show it from the non-main thread, then it is likely a dead lock due to how Windows deals with messages and threads.
When a window handle is created it is tied to the thread on which it was created. This means that Windows will ensure that any messages sent to that handle are processed on that thread.
I would strongly suggest you read up on how window messages, message queues, and handles all interact and function in a multi-threaded environment. If not done correctly, you are assured of some very odd and possibly unpredictable behavior.
I would call your condition either a Race, a Deadlock, or some other kind of error like that. As Allen says, if the background thread makes ANY direct access to the VCL controls, without using TThread.Synchronize(myMethod) to invoke the myMethod that touches your VCL foreground, then this alone would cause your trouble.
Post more information, including a sample of your code please.