WinRT/C++ Run long for loops without causing UI freeze - c++-winrt

Is there a specific way to run long for loops without causing UI freezes on desktop applications using WinRT/C++ libraries?
The goal is that users can still switch pages without having to wait for the previous page using a long for loop to finish loading.

You can use winrt::resume_background to offload the code following into the Windows threadpool, e.g.
winrt::Windows::Foundation::IAsyncAction ExampleAsync()
{
winrt::apartment_context uiThread;
// run the following code in a Windows threadpool thread.
co_await winrt::resume_background();
// long-running code here
for (...)
{
...
}
// if you want to switch to the UI thread again:
co_await uiThread;
// do things on the UI thread
...
}

Related

Xamarin Xaml force update interface elements

The post has been rewritten to better fit the current problem.
I have a button x:Name="selectVesselButton". On button click, it tries to establish a connection to a server, which takes a sec or two for to do. Originally, I wanted the button to be grayed out while it was downloading and deserializing the json file from the connection.
My old code (before async, and trying to update the button):
// disabling the button to prevent spam clicking.
string buttonText = selectVesselButton.Text;
selectVesselButton.IsEnabled = false;
selectVesselButton.Text = "loading...";
// retrieve data for speed page.
RetrieveData();
// redirect to next info block if build was successfull.
FocusSpeedblock();
// enabling the button again.
selectVesselButton.Text = buttonText;
selectVesselButton.IsEnabled = true;
The issue with this code was that the button visuals did not update until the RetrieveData() was finished, defeating the purpose of doing that at all. This was because the code for updating the interface and the code for downloading and deserializing the object were both on the same thread.
However, following Ivan's advice, I made the downloading and deserializing Async, which fixed this issue (more like moved it).
This works fairly well, but I am still having some trouble updating the interface automatically. I have some labels that need to be updated based on the json file output. The value of the labels update on the background, but only update visually once I interact with the labels (I.E. scrolling the scrollview they are on). Check edit 3 for more detail on that.
EDIT 3:
When the second thread is finished, it should call the UpdateSpeedLabels() and update some labels. However, they update in codebehind, without instantly updating the interface. They only update if I interact with those labels.
The preferred way of doing this on Xamarin is with data binding. As you opted out of this it is still possible.
What you need is to ensure that your long task is not running in the UI thread as it blocks it and prevent its updates. You do this by using Task.Run(() => { your task code }); . However you can't update your user interface inside the Task.Run as it is not running on the UI thread and it would crash the app, so you need to use Device.BeginInvokeOnMainThread(() => { your UI code }); inside Task.Run for that part.

How to call a method on the GUI thread in C++/winrt

When responding to an event in a textbox using C++/winrt I need to use ScrollViewer.ChangeView(). Trouble is, nothing happens when the call executes and I expect that is because at that moment the code is in the wrong thread; I have read this is the cause for lack of visible results from ChangeView(). It appears that the proper course is to use CoreDispatcher.RunAsync to update the scroller on the UI thread. The example code for this is provided only in C# and managed C++, however, and it is a tricky matter to figure out how this would look in normal C++. At any rate, I am not getting it. Does anyone have an example of the proper way to call a method on the UI thread in C++/winrt? Thanks.
[UPDATE:] I have found another method that seems to work, which I will show here, though I am still interested in an answer to the above. The other method is to create an IAsyncOperation that boils down to this:
IAsyncOperation<bool> ScrollIt(h,v, zoom){
co_await m_scroll_viewer.ChangeView(h,v,zoom);
}
The documentation entry Concurrency and asynchronous operations with C++/WinRT: Programming with thread affinity in mind explains, how to control, which thread runs certain code. This is particularly helpful in context of asynchronous functions.
C++/WinRT provides helpers winrt::resume_background() and winrt::resume_foreground(). co_await-ing either one switches to the respective thread (either a background thread, or the thread associated with the dispatcher of a control).
The following code illustrates the usage:
IAsyncOperation<bool> ScrollIt(h, v, zoom){
co_await winrt::resume_background();
// Do compute-bound work here.
// Switch to the foreground thread associated with m_scroll_viewer.
co_await winrt::resume_foreground(m_scroll_viewer.Dispatcher());
// Execute GUI-related code
m_scroll_viewer.ChangeView(h, v, zoom);
// Optionally switch back to a background thread.
// Return an appropriate value.
co_return {};
}

iOS app behaves differently with debug vs release scheme

In my app I have three internet operations that run at once. They don't depend on each other so I run each of them in a background thread. They each need to be complete though before my app can move on to the completion handler.
The method that starts each of the three receives as a parameter, block code that functions as a completion handler. This method also has a local variable called internetOperationsRemaining that I set equal to 3 before I start each of the three internet operations.
When each of the internet operations is complete I decrement internetOperationsRemaining on the main thread. This results in internetOperationsRemaining == 0 when they are all complete.
To listen for this condition I run a tight loop on another background thread that simply loops on itself waiting for internetOperationsRemaining to equal 0. Once that happens I call the completion handler that was passed in as a parameter as previously described.
//Spawn a background thread and loop in it until
//allInternetOperationComplete == true.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while(internetOperationsRemaining > 0)
{
//Just spins in here on a background thread waiting
//on the internet to finish.
}
//Now that internetOperationsRemaining == 0, kill the NSURL session
//and call the completion handler on the main thread.
dispatch_async(dispatch_get_main_queue(), ^{
[session finishTasksAndInvalidate];
completionHandler();
});
});
The strange behavior that I am seeing is that the app runs perfectly if I have debug set in the scheme, and it doesn't if I have release selected. It simply never breaks out of the while loop.
If I insert some trivial code in the while loop to slow things down just a little it works fine in both debug and release.
while(internetOperationsRemaining > 0)
{
//Just spins in here on a background thread waiting
//on the internet to finish.
int i=0;
++i;
}
I am at a loss to explain this behavior. The tight loop is on a background thread so the app remains responsive to user input as would be expected. I realize that the release scheme introduces optimizations, but I am surprised it actually changed the apps behavior.
Without running code to check, I would think that what is going on is some sort of compiler optimisation which only occurs in Release code.
I think the real problem though is more about design. Using counters and having a thread spinning is not great. I would suggest looking into using NSOperations. You can setup hierarchies of operations so that your completion operation is dependant on the other three. Go read up on using operations, concurrent queues and dependencies and you will get the idea.

How Do I Pause a System.Timer in Visual Basic?

I am using a system.timer in a Windows Service to run a process that usually exceeds the timer's interval. I am trying to keep the timer from firing the same code more than once, a known issue with system.timers.
What I want: The timer runs my code, but the timer "pauses" to wait until the code is completed before resuming ticks.
I have two problems:
The way system.timers work is that the timer will create a race condition on you by launching new redundant threads of the same code and pile them up on you if the has not completed by the time the timer's interval has elapsed.
I would start/stop the timer to keep this from happening, but with a System.Timers.Timer, once you stop the timer for the processing to complete, it never comes back - I have never been able to restart a timer once it has been stopped, it has been destroyed and likely collected. Enabling/disabling is the same exact thing as start/stop with same results.
How on earth do you keep a system.timer from launching new redundant threads of the same code if the process has not completed by the time the timer's interval has lapsed? Obviously, starting/stopping (enabling/disabling) the timer is NOT a solution, as it doesn't work.
Help!
Start your timer when it needs to start, kick off another thread to do the work after which the timer can be stopped. The timer won't care if the thread completed or ran away with the prize money. Use Task Parallel Library (TPL) for the most effective usage.
The Start and Stop methods on the Timer do actually work in a Windows service.
I have multiple production services which use code that do that, except my code is written in C#.
However, make sure you are using the System.Timers.Timer and not the Windows.Forms.Timer
Here's a quick example of C# / pseudocode of what my services look like.
// this is the OnStart() event which fires when windows svc is started
private void OnStart()
{
// start your timer here.
MainTimer.Start();
}
private void ElapsedEventHandler()
{
try
{
// Stop the timer, first thing so the problem of another timer
// entering this code does not occur
MainTimer.Stop();
//Do work here...
}
catch (Exception ex)
{
// if you need to handle any exceptions - write to log etc.
}
finally
{
MainTimer.Start();
// finally clause always runs and will insure
// your timer is always restarted.
}
}

How best execute query in background to not freeze application (.NET)

My WinForm apps needs to execute complex query with significant execution time, I have no influence (about 10mins)
When query is executing user sees 'application not responding' in task manager, which is really confusing to user, also not very professional...
I believe that query shall be executed in different thread or so. Have tried some approaches but have difficulties to make it really working (execute query, force main application wait result, return back to main app, possibility to cancel execution etc)
I wonder if you have own / good working solution for that. Code samples would be also very welcome :)
Also I believe there might exist some ready to use utilities / frameworks allowing simple execution of that.
The simplest approach here would be to do that work from a BackgroundWorker. MSDN has examples for this. This then executes on a worker thread, with events for completion/error/etc. It can also support cancel, but your operation needs to be coded to be interruptable.
Another approach is the Task API in 4.0; but if you use this you'll need to get back to the UI thread (afterwards) yourself. With BackgroundWorker this is automatic (the events are raised on the UI thread).
If ExecuteQuery if the method you want to execute, you can do:
void SomeMethod() {
var thread = new Thread(ExecuteQuery);
thread.Start();
}
void ExecuteQuery() {
//Build your query here and execute it.
}
If ExecuteQuery receives some parameters, like:
void ExecuteQuery(string query) {
//...
}
You can do:
var threadStarter = () => { ExecuteQuery("SELECT * FROM [Table]"); };
var thread = new Thread(ThreadStarter);
thread.Start();
If you want to stop the execution of the background thread, avoid calling thread.Abort() method. That will kill the thread, and you do not want this, because some incosistency could appear in your database.
Instead, you can have a bool variable visible from ExecuteQuery and from outside you can set it to True when you want to stop it. Then all you have to do is check in some parts of the code inside ExecuteQuery if that variable is still True. Otherwise, do some rollback to maintain the database stable.
Be sure you set that bool variable volatile
Edit:
If you want the UI to wait from the background thread, I usually do:
Start the background thread
Start some progress bar in the UI
Disable some controls (like buttons, etc) to avoid the user to click them while the background thread is working (eg: If you're executing the thread when a user clicks a button, then you should disable that button, otherwise multiple queries will be ocurring at the same time).
After finished the thread, you can stop progress bar and enable controls again.
How to know when the thread finished? You can use Events for that. Just create an event and fire it when it finishes, and do whatever you want inside the event handler...
Be sure you're accessing correctly to UI controls from the background thread, otherwise it will give you an error.
If you are new to threads and task is simple (as it seems), you should try to use standard background worker component.