So I have a "command queue" running that pumps messages out to a TCP server in my app. When the app goes to sleep, I stop the queue. When it resumes, I restart the queue. The Start and StopQueue functions are below.
public void StartQueue()
{
Task.Run(async () =>
{
while (true)
{
if (_cancellationToken.IsCancellationRequested)
{
break;
}
await Task.Delay(Hz10);
await UpdateAsync();
}
}, _cancellationToken);
}
public void StopQueue()
{
if (_cancellationToken.IsCancellationRequested) return;
_cancellationTokenSource.Cancel();
}
I can verify through the debugger that the queue is stopped successfully when the app goes to sleep (for example, pressing Home on an iPhone twice). I can also verify through the debugger that StartQueue is called when the app resumes (regains focus). However, none of my breakpoints in the Task.Run are hit after that. This leads me to believe the thread is not actually being recreated, as no breakpoints are hit in UpdateAsync or the task itself after resume.
Just make sure to initialize a new instance of _cancellationToken prior to calling StartQueue otherwise the Task will never run because the token is already in cancelled state.
Related
What happens if in an Azure Function an async Task is started but orphaned before it finishes (it is never awaited), e.g.:
[Function("FuncAsync")]
public static async Task<HttpResponseData> FuncAsync(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = "FuncAsync")]
HttpRequestData req,
FunctionContext context)
{
var obj = FactoryClass.GetObject(); // return some object with async LongTaskAsync method
obj.LongTaskAsync(); // async Task LongTaskAsync()
return req.CreateResponse(HttpStatusCode.OK);
}
The intention here was (I guess) to initiate a long running process and instantly return from the function.
I assume it is a bad practice but seems to work in a legacy code. I suspect there's no guarantee for the life of that async task and the azure process can be randomly winded up, when no function entry point is running/triggered.
For a console application if a running async Task is orphaned (and keeps running while the process terminates) it is abandoned/killed (and no exception is thrown).
class Program
{
public static async Task RunFuncAsync()
{
try
{
Console.WriteLine("Task started.");
await Task.Delay(10 * 1000);
Console.WriteLine("Task finished."); // this is never executed
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e.Message); // this is never executed
}
}
static async Task MainAsync(string[] args)
{
var t = RunFuncAsync(); // no awaiting - purposefuly
await Task.Delay(5 * 1000);
Console.WriteLine("Exiting.");
}
static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
}
}
Output:
Task started.
Exiting.
C:\TestTasks_Console.exe (process 6528) exited with code 0.
To automatically close the console when debugging stops, enable Tools->Options->Debugging->Automatically close the console when debugging stops.
Press any key to close this window . . .
What happens if in an Azure Function an async Task is started but
orphaned before it finishes ?
The answer for the above question which you have is correct that it will get terminated. Azure Functions have many features that make our work a lot easier. However, stateless Azure Functions are not suitable for long running operations which would require to store a state of progress.
For such cases the Durable Functions are the best option. With this the restrictions on execution times no longer apply.
The task-based programming model and async/await are well suited for mapping workflows of Durable Functions.
If you check the Azure Function best practices, you will also find that we should avoid long running function and our function should be stateless.
Another option is to go for the WebJobs. You can use Azure WebJobs to execute custom jobs as background tasks within an Azure Web App
In conclusion, we can say that stateless Azure Functions not recommended for long running operations as you may get timeout issues or like in your case may get terminated.
I have a logger which runs on it's own thread to prevent slowing down the main thread. Making it single-threaded would be easier, but I have a lot of slow code (writing to multiple files, getting info from stacktraces) and so on. The order of execution is:
Main thread
Logger.Log("foo"); //Creates stack trace for me
//Message and stack trace get added to queue
Logger thread (in while loop)
//Sees queued message
//Formats it (slow)
//Writes it to (one or more) streams and the console (*very* slow)
My problem is that if I make the logger thread a foreground thread, it prevents the app from closing once Main finishes, but if I make it background, it often gets cut off and doesn't manage to write most of the messages that were logged recently. Is there any way to make a function that will 'flush' the queue run just before the app quits, while keeping the thread background? (I can't always assume that people using my library will call a function before the app quits, and in certain cases (cough Unity cough) they really don't have much control)
You need some kind of synchronization between your threads. Instead of using your own Threads, consider using Tasks, these still run as Threads. From inside the main thread you can wait for the other tasks to finish or even signal them using a CancellationTokens.
When your "other logger thread" gets the Cancellation it can flush and exit it's log.
Here's a demo using Serilog with the Console Sink, you would probably want to use two different ILogger instances.
static async Task OtherLoggerAsync(CancellationToken ct)
{
await Task.Yield();
// This method is now running on it's own thread
while (true)
{
Log.Information("Other logger logged on thread");
await Task.Delay(750); // Mimic some work
if (ct.IsCancellationRequested)
{
Log.Logger.Information("OtherLoggerAsync() exiting");
break;
}
}
}
static async Task Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
using (CancellationTokenSource cts = new CancellationTokenSource())
{
// Create the cancellation token
var ct = cts.Token;
// Start the other logger with the cancellation token
var t = OtherLoggerAsync(ct);
// Still in the main thread
for (var i = 0; i < 10; i++)
{
Log.Logger.Information("Main thread logged");
await Task.Delay(1000); // Mimic some work
}
// Main thread has finished. We want to stop the OtherLogger Thread
// if it has finsihed or not.
// signal the cancellation
cts.Cancel();
// wait for it to finish
Task.WaitAll(t);
Log.Logger.Information("Main thread exiting");
Log.CloseAndFlush();
}
}
I have an application that works but after a while when I debug on my iPhone it hangs the phone and the only way I can recover is a hard reset of the button on the side and the home button.
First of all, could that be because my application has a memory leak?
Here's the code for the application. In particular, I am looking at the BeginInvokeOnMainThread method. Can someone tell me if they can see if there could be any problems with the way that it is implemented? Also, what's the purpose of the .ContinueWith((arg).
namespace Japanese
{
public partial class PhrasesFrame : Frame
{
CancellationTokenSource cts = new CancellationTokenSource();
public PhrasesFrame(PhrasesPage phrasesPage)
{
InitializeComponent();
this.phrasesPage = phrasesPage;
AS.phrasesFrame = this;
Device.BeginInvokeOnMainThread(() => ShowCards(cts.Token).ContinueWith((arg) => { }));
}
public void Disappearing()
{
cts.Cancel();
}
public async Task ShowCards(CancellationToken ct)
{
AS.cardCountForSelectedCategories = App.DB.GetCardCountForSelectedCategories();
while (!ct.IsCancellationRequested)
{
await Task.Delay(500);
}
}
}
}
ContinueWith
First, let's address your question about .ContinueWith((arg) => { })). ContinueWith tells more code to execute once the original Task has completed. In our case, the code inside of ContinueWith will run once Device.BeginInvokeOnMainThread(() => ShowCards(cts.Token) has finished.
In this case, there is no code inside of ContinueWith, so we can remove it.
Freezing
Yes, I can see that this code has potential to freeze the UI.
BeginInvokeOnMainThread will queue an Action to run on the Main Thread (also known as the UI Thread). The Main Thread is constantly listening for user input (tapping a button on the screen, pinch-to-zoom, etc.), and if this thread is busy doing a long-running task, it will not be able to respond to a user's input until it has finished; thus your app will appear frozen.
The code await Task.Delay(500); is being called by the Main Thread. We are thus telling the Main Thread to freeze itself for 500 milliseconds, and looping that indefinitely.
One solution would be to wrap this code in Task.Run which would put it in a background-thread and free the Main Thread to listen/respond to user input.
Task.Run(async () =>
{
while (!ct.IsCancellationRequested)
{
await Task.Delay(500);
}
}
More Threading Recommendations
Only use BeginInvokeOnMainThread when you need to update the UI. 99% of code can run on a background thread with no problems. The 1%, however, is code that updates the UI; any code that updates the UI must be run on the Main Thread.
If a task that takes longer than the refresh rate of the screen to execute, perform it on a background thread. For example, if the screen's refresh rate is 60Hz, it is updating 60-times per second, every 16.7ms. So if we have a block of code that takes 20ms to execute, we need to execute it on a background thread to ensure that we don't freeze the app and drop any frames.
The code above looks like it is accessing a database, which I would highly recommend moving to a background thread like so
await Task.Run(() => AS.cardCountForSelectedCategories = App.DB.GetCardCountForSelectedCategories());
First, if you are concerned about a memory leak, you can check for low-memory warnings in the device logs (accessible through XCode), or override the ReceiveMemoryWarning method in your app delegate to log an error.
Secondly, there's nothing obviously wrong with the way you're calling BeginInvokeOnMainThread that would cause a leak. The ContinueWith is a no-op that doesn't affect the operation of the code - I'm guessing it's there to avoid a compiler warning that you're not awaiting the task.
Thirdly, if you suspect that this code is causing a leak, you should use logging and/or breakpoints to confirm that it's behaving as expected. Is the task correctly cancelled when you navigate away from the page? Do you see multiple instances of of the ShowCards task running? If this code turns out to be behaving correctly, then the source of the hang lies elsewhere in your app. For instance, it looks like you're making a database call twice a second - maybe it's not cleaning up resources properly.
I just started playing with my fresh Raspberry Pi 3 and Win10 IOT.
I tried a little project but encountered some problems with async/await statements.
I am not new to C#, nor with await/async, but it is my first time with UWP so I may miss some tricks for this platform compairing to the WinForms/WPF environment.
(FYI, I haven't access to a Win10 developpement machine for the moment, so below snippets may not compile right away)
Here is the standard template for a headless application on the Rpi :
public async void Run(IBackgroundTaskInstance taskInstance)
{
taskInstance.GetDeferral();
await DoSomethingAsync();
// Other irrevelant stuff then...
defferal.Complete();
}
And then an async method :
private async Task DoSomethingAsync()
{
// Something done async
await Task.Delay(1000);
} // <--- Hangs here
When deploying the app to the Pi, it enters the DoSomethingAsync method and execute its content without problem.
My issue is that the app hangs at the exiting semicolon.
Do we need to use the CoreDispatcher, the ThreadPool, or a simple new TaskFactory().StartNew(async () => { await DoSomethingAsync(); }); ?
What I don't understand is the use of the await/async should execute my method on an other thread, but it hangs the same way as if it was waiting for UI to process messages queue (WinForms/WPF background here :) )
Thank you in advance.
EDIT : This snippet works if I remove all the async stuff to make it synchronously running.
I don't see Complete() method on defferal in your code, try this:
public async void Run(IBackgroundTaskInstance taskInstance)
{
BackgroudTaskDefferal defferal = taskInstance.GetDeferral();
await DoSomethingAsync();
// Other irrevelant stuff then...
defferal.Complete();
}
That could be problem with hanging, application's waiting for signal that async operations are completed.
If you remove all the breakpoints, add debugging logs like
`System.Diagnostics.Debug.WriteLine`
The debug message would show everything is working all fine.
The hang only happens when you do the remote debugging with VS.
I suggest you open an user voice request.
So after a long time of cursing and giving up hope I got everything to work (almost).
I have a GUI which displays a list of connected addresses and a list of messages. Normally when I close a connector (disconnect from an address) I write a message saying: "disconnected from address x". However as you will see from the methods, when disposing the application I cannot use the dispatcher to write that message (this.ModuleConnections.Remove(address); triggers the writing of the message and also removes it visually from the list).
private void CloseConnector(string address)
{
Task task = new Task(() =>
{
var moduleConnection = this.ModuleConnections[address];
moduleConnection.ModuleConnector.Dispose();
if (mDisposed == true)
{
ApplicationSupport.Dispatcher.Invoke(
DispatcherPriority.Background,
new Action(() =>
{
this.ModuleConnections.Remove(address);
}));
}
});
task.Start();
if (mDisposed == true)
{
mTasks.Add(task);
}
}
protected virtual void Dispose(bool disposing)
{
// Dispose managed resources.
if ((mDisposed == false) && (disposing == true))
{
mTasks.Clear();
mDisposed = true;
CloseConnectors();
Task.WaitAll(mTasks.ToArray());
}
}
I cannot use the dispatcher because Task.WaitAll stops the thread. If the thread is stopped the dispatcher cannot execute this.ModuleConnections.Remove(address); and this results in the task not finishing, if the tasks not finish Task.WaitAll won't release the thread. Which is a very big problem.
Without the task.waitall i would get a tremendous amount of object disposed and key not found exceptions and other nasty things which kept some threads running and thus the application wouldn't shut down completely.
But now, when it closes, the GUI freezes (looks like it crashed) for a few seconds and then (when task.waitall is finished) it closes the window and the entire application is closed correctly.
What I want is to still be able to update my list of messages and display what addresses have disconnected.
Just to clarify
I need the Task in the CloseConnector method because closing the connector (dispose) makes it disconnect, it needs to wait until it receives a message back from the other side before the code continues. if i were to run this 1 by one it would take minutes, in parallel as i do it now it only takes a few seconds.
First thing that I saw that you do not need to call Start() method for your task if you want to tun them all with WaitAll() menthod. Also if you want to run one task at a time, its better to use Task.Run() which takes Expression as an argument. The difference in this case is that Run() forces your task to start immediately while Start() can not guarantee that your task will be started now - it's just plan it to start with TaskScheduler. By the way, Wait() work in the same way
Finally, check your this object - what is this at this time? Is it not null? Maybe try to use closure and take your dispatcher as an arg
Hope that helps