UWP is way over my head and sorry for this question.
Why is a file create blocking my UWP from loading?
public static async Task CreateFile()
{
StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
var item = await ApplicationData.Current.LocalFolder.TryGetItemAsync("sFile.xml");
if (item == null)
{
StorageFile file = await storageFolder.CreateFileAsync("sFile.xml");
await FileIO.WriteLinesAsync(file, GlobalVars.fileStrings);
}
}
This function is called from my main method
The CreateFile function never returns. Why is that?
Edit: Added main method
public GroupedItemsPage()
{
this.InitializeComponent();
this.navigationHelper = new NavigationHelper(this);
this.navigationHelper.LoadState += navigationHelper_LoadState;
try
{
SampleDataSource.CreateFile().Wait();
Debug.WriteLine("Continue");
}
catch (Exception ex)
{
var msg = new MessageDialog(ex.StackTrace);
Task.Run(async () => { await msg.ShowAsync(); }).Wait();
throw ex.InnerException;
}
GlobalVars.LastFreeSignalCheckTimer.Tick += SampleDataSource.LastFreeSignalCheckTimer_Tick;
GlobalVars.LastFreeSignalCheckTimer.Interval = new TimeSpan(0, 0, 0, 120);
GlobalVars.LastFreeSignalCheckTimer.Start();
}
I think the problem is the .Wait() from your SampleDataSource.CreateFile().Wait(); use await SampleDataSource.CreateFile(); instead.
Wait() is a blocking operation you must be careful if you want to use it because you can easy build a deadlock. In most situations await is the better choice.
In this case you are blocking the UI thread with your Wait() so that the successful execution of the CreateFile() method in the same thread is prevented. With an await instead your code should work because the thread is not blocked while you wait so that other code (like your CreateFile()) can be executed.
Another solution is to use Task.Run to execute the method in background so that you can wait with Wait() because the method is not executed in the same blocked thread (but it would still be ugly code design to block the whole UI thread).
You are running into a deadlock. That's why you should never block on async code.
Instead of calling the async CreateFile method in the constructor of the Page, which is bad practice, you could call it once the page has been initialized by handling the Loaded event of the page. Then you can await the async methods as you should:
public sealed partial class GroupedItemsPage : Page
{
public GroupedItemsPage()
{
this.InitializeComponent();
this.navigationHelper = new NavigationHelper(this);
this.navigationHelper.LoadState += navigationHelper_LoadState;
this.Loaded += GroupedItemsPage_Loaded;
}
private async void GroupedItemsPage_Loaded(object sender, RoutedEventArgs e)
{
try
{
await SampleDataSource.CreateFile();
Debug.WriteLine("Continue");
}
catch (Exception ex)
{
var msg = new MessageDialog(ex.StackTrace);
await msg.ShowAsync();
throw ex.InnerException;
}
GlobalVars.LastFreeSignalCheckTimer.Tick += SampleDataSource.LastFreeSignalCheckTimer_Tick;
GlobalVars.LastFreeSignalCheckTimer.Interval = new TimeSpan(0, 0, 0, 120);
GlobalVars.LastFreeSignalCheckTimer.Start();
}
}
Related
I have a strange behavior that I can't manage to explain.
In an async function, an awaited call blocks forever.
Note: it seams that the problem occurs since I moved from a console app to a Windows Form. (the call is called from the constructor of Form1().
_client is the HttpClient dotnet class.
public async Task GetConfigurationFile()
{
var stringContent = new StringContent(JsonConvert.SerializeObject(companyKey), Encoding.UTF8, "application/json");
HttpResponseMessage response = null;
// This call works and returns the respons after a few milliseconds
response = _client.PostAsync(_configurationFileEndpoint, stringContent).Result;
// The same awaited call block forever and never returns.
response = await _client.PostAsync(_configurationFileEndpoint, stringContent);
}
public Form1()
{
InitializeComponent();
_engine = new Engine();
}
public Engine()
{
// Logic similar to this.
Configuration configuration = null;
try
{
using (var reader = new StreamReader(Directory.GetCurrentDirectory() + "/configuration.json"))
{
configuration = Newtonsoft.Json.JsonConvert.DeserializeObject<Configuration>(reader.ReadToEnd());
}
}
catch (Exception ex)
{
// Something done
}
_apiCall = new PlatformCommunication(configuration);
if (configuration == null)
{
try
{
_apiCall.GetConfigurationFile().Wait();
}
catch (Exception exc)
{
}
}
}
You are doing this:
_apiCall.GetConfigurationFile().Wait();
As explained in many places, such as here - blocking on async code from UI thread is bad idea. When you have this:
response = await _client.PostAsync(_configurationFileEndpoint, stringContent);
the SynchronizationContext will be captured before await and execution after await will continue on that context, which means in this case on UI thread. It cannot continue there, because UI thread is blocked by GetConfigurationFile().Wait(), so you have deadlock.
When you have this:
response = _client.PostAsync(_configurationFileEndpoint, stringContent).Result;
The code inside PostAsync uses ConfigureAwait(false) on every async call, to prevent continuations running on captured context. So all continuations run on thread pool threads and you can get away with blocking on async call with Result in this case (doesn't make it good idea still). Then after this change your GetConfigurationFile becomes synchronous (there is no await left), so you can get away with Wait() also.
You can do the same ConfigureAwait(false):
response = await _client.PostAsync(_configurationFileEndpoint, stringContent).ConfigureAwait(false);
And it will help in this case, but that's not the way to solve this problem. The real way is to just not block on async code on UI thread. Move _apiCall.GetConfigurationFile() outside of constructor.
#YK1: to prevent blocking calls, I can move the code in the
constructor of Engine() to an Async Initialize function and await
_apiCall.GetConfigurationFile() instead of_apiCall.GetConfigurationFile().Wait(); But then in my Winform, I
need to await engine.Initialize() from an Async function which I don't
have? ( engine must run automatically, not be behind a start button),
reason why I put it in the constructor of the form which is not async.
Instead of constructor, move your startup code code to an async method. You can subscribe to Form_Load event and call that method.
class Engine
{
public async Task Init()
{
// Logic similar to this.
Configuration configuration = null;
try
{
using (var reader = new StreamReader(Directory.GetCurrentDirectory() + "/configuration.json"))
{
configuration = Newtonsoft.Json.JsonConvert.DeserializeObject<Configuration>(reader.ReadToEnd());
}
}
catch (Exception ex)
{
// Something done
}
_apiCall = new PlatformCommunication(configuration);
if (configuration == null)
{
try
{
await _apiCall.GetConfigurationFile();
}
catch (Exception exc)
{
}
}
}
}
and
private async void Form_Load(object sender, EventArgs e)
{
_engine = new Engine();
await _engine.Init();
}
I am trying to use the following technique to be able to have a worker task executing some operations, with a 10 sec timeout and without blocking the application.
internal void ReadAll()
{
var data = new byte[1];
Task.Factory.StartNew(() =>
{
var ct = new CancellationTokenSource();
var ReadAllTask = Task.Factory.StartNew(() =>
{
// Read all information
// [omit communication exchange via COM port]
ct.Cancel();
}, ct.Token);
// First thread waiting 10s for the worker to finish
ReadAllTask.Wait(10000, ct.Token);
if (ReadAllTask.Status == TaskStatus.RanToCompletion)
{
ReadAllComplete?.Invoke(true);
}
else
{
ct.Cancel();
ReadAllComplete?.Invoke(false);
}
});
}
This method is called by pressing a button. It seems to me that in debug configuration works properly, but not in release configuration where the "first thread" never reach the wait and no event is thrown.
Your code could be a lot simpler than current version. Easiest way to make a non-blocking method for event is to mark it with async keyword and use the await keyword to start the asynchronous read operation from SerialPort.BaseStream property.
Also, CancellationTokenSource could be created with time, after that it get cancelled automatically, and the right way to cancel is to call CancellationToken.ThrowIfCancellationRequested method. async/await mechanism will invoke the event in UI context, so code could be something like this:
// async void is a recommended way to use asynchronous event handlers
private async void btnReadAll_Click(object sebder, EventArgs e)
{
var data = new byte[2];
// cancel source after 10 seconds
var cts = new CancellationTokenSource(10000);
// Read all information
// [omit communication exchange via COM port]
// async operation with BaseStream
var result = await SerialPort.BaseStream.ReadAsync(data, 0, 2, cts.Token);
/*
* if you can't use the BaseStream methods, simply call this method here
* cts.Token.ThrowIfCancellationRequested();
*/
// this code would run only if everything is ok
// check result here in your own way
var boolFlag = result != null;
ReadAllComplete?.Invoke(boolFlag);
}
Here's just a quick rewrite to remove the event and wrap what appears to be a synchronous IO API in an async one. If at all possible you should switch to a true async API and drop the Task.Run.
private CancellationTokenSource cts;
public async void MyButtonhandler(object sender, EventArgs e) {
cts = new CancellationTokenSource();
try {
var result = await Task.Run(() => ReadAll(cts));
if (result) {
//success
} else {
//failure
}
} catch (TaskCanceledException ex) {
}
}
internal async Task<bool> ReadAll(CancellationTokenSource cts) {
byte[] data = new byte[1];
var timeout = TimeSpan.FromSeconds(10);
var ReadAllTask = Task.Run(() => {
// Read all information
// [omit communication exchange via COM port]
}, cts.Token);
if (await Task.WhenAny(ReadAllTask, Task.Delay(timeout)) == ReadAllTask) {
return true;
}
cts.Cancel();
return false;
}
Reading comments and answers to my question I learned a couple of useful things that solve my problem:
CancellationTokenSource can have an implicit timeout
use Task.Run instead Task.Factory.StartNew
don't need to cancel the task, the cts will do the work
Now my code is simpler and it works:
private void Read_All_Button_Click(object sender, RoutedEventArgs e)
{
// Start timedout task that will send all necessary commands
CancellationTokenSource cts = new CancellationTokenSource(10000);
Task.Run(() =>
{
oCommandSets.ReadAll(cts);
}, cts.Token);
}
and
internal void ReadAll(CancellationTokenSource cts)
{
// [communication]
if (cts.IsCancellationRequested)
{
ReadAllComplete?.Invoke(false);
}
else
{
ReadAllComplete?.Invoke(true);
}
}
In any case I need to learn more about multithreading.
I have a few tests with WebBrowser control wrapped with MessageLoopWorker as described here: WebBrowser Control in a new thread
But when another test creates user control or form, the test freezes and never completes:
[Test]
public async Task WorksFine()
{
await MessageLoopWorker.Run(async () => new {});
}
[Test]
public async Task NeverCompletes()
{
using (new Form()) ;
await MessageLoopWorker.Run(async () => new {});
}
// a helper class to start the message loop and execute an asynchronous task
public static class MessageLoopWorker
{
public static async Task<object> Run(Func<object[], Task<object>> worker, params object[] args)
{
var tcs = new TaskCompletionSource<object>();
var thread = new Thread(() =>
{
EventHandler idleHandler = null;
idleHandler = async (s, e) =>
{
// handle Application.Idle just once
Application.Idle -= idleHandler;
// return to the message loop
await Task.Yield();
// and continue asynchronously
// propogate the result or exception
try
{
var result = await worker(args);
tcs.SetResult(result);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
// signal to exit the message loop
// Application.Run will exit at this point
Application.ExitThread();
};
// handle Application.Idle just once
// to make sure we're inside the message loop
// and SynchronizationContext has been correctly installed
Application.Idle += idleHandler;
Application.Run();
});
// set STA model for the new thread
thread.SetApartmentState(ApartmentState.STA);
// start the thread and await for the task
thread.Start();
try
{
return await tcs.Task;
}
finally
{
thread.Join();
}
}
}
The code steps-in well except return await tcs.Task; never returns.
Wrapping new Form into the MessageLoopWorker.Run(...) seems to make it better, but it does not work with more complicated code, unfortunately. And I have quite a lot of other tests with forms and user controls that I would like to avoid wrapping into messageloopworker.
Maybe MessageLoopWorker can be fixed to avoid the interference with other tests?
Update: following the amazing answer by #Noseratio I've reset the synchronisation context before the MessageLoopWorker.Run call and it now works well.
More meaningful code:
[Test]
public async Task BasicControlTests()
{
var form = new CustomForm();
form.Method1();
Assert....
}
[Test]
public async Task BasicControlTests()
{
var form = new CustomForm();
form.Method1();
Assert....
}
[Test]
public async Task WebBrowserExtensionTest()
{
SynchronizationContext.SetSynchronizationContext(null);
await MessageLoopWorker.Run(async () => {
var browser = new WebBrowser();
// subscribe on browser's events
// do something with browser
// assert the event order
});
}
When running the tests without nulling the sync context WebBrowserExtensionTest blocks when it follows BasicControlTests. With nulling it pass well.
Is it ok to keep it like this?
I repro'ed this under MSTest, but I believe all of the below applies to NUnit equally well.
First off all, I understand this code might have been taken out of context, but as is, it doesn't seem to be very useful. Why would you want to create a form inside NeverCompletes, which runs on an random MSTest/NUnit thread, different from the thread spawned by MessageLoopWorker?
Anyhow, you're having a deadlock because using (new Form()) installs an instance of WindowsFormsSynchronizationContext on that original unit test thread. Check SynchronizationContext.Current after the using statement. Then, you facing a classic deadlock well explained by Stephen Cleary in his "Don't Block on Async Code".
Right, you don't block yourself but MSTest/NUnit does, because it is smart enough to recognize async Task signature of NeverCompletes method and then execute something like Task.Wait on the Task returned by it. Because the original unit test thread doesn't have a message loop and doesn't pump messages (unlike is expected by WindowsFormsSynchronizationContext), the await continuation inside NeverCompletes never gets a chance to execute and Task.Wait is just hanging waiting.
That said, MessageLoopWorker was only designed to create and run WinForms object inside the scope of the async method you pass to MessageLoopWorker.Run, and then be done. E.g., the following wouldn't block:
[TestMethod]
public async Task NeverCompletes()
{
await MessageLoopWorker.Run(async (args) =>
{
using (new Form()) ;
return Type.Missing;
});
}
It was not designed to work with WinForms objects across multiple MessageLoopWorker.Run calls. If that's what you need, you may want to look at my MessageLoopApartment from here, e.g.:
[TestMethod]
public async Task NeverCompletes()
{
using (var apartment = new MessageLoopApartment())
{
// create a form inside MessageLoopApartment
var form = apartment.Invoke(() => new Form {
Width = 400, Height = 300, Left = 10, Top = 10, Visible = true });
try
{
// await outside MessageLoopApartment's thread
await Task.Delay(2000);
await apartment.Run(async () =>
{
// this runs on MessageLoopApartment's STA thread
// which stays the same for the life time of
// this MessageLoopApartment instance
form.Show();
await Task.Delay(1000);
form.BackColor = System.Drawing.Color.Green;
await Task.Delay(2000);
form.BackColor = System.Drawing.Color.Red;
await Task.Delay(3000);
}, CancellationToken.None);
}
finally
{
// dispose of WebBrowser inside MessageLoopApartment
apartment.Invoke(() => form.Dispose());
}
}
}
Or, you can even use it across multiple unit test methods, if you're not concerned about potential coupling of tests, e.g. (MSTest):
[TestClass]
public class MyTestClass
{
static MessageLoopApartment s_apartment;
[ClassInitialize]
public static void TestClassSetup()
{
s_apartment = new MessageLoopApartment();
}
[ClassCleanup]
public void TestClassCleanup()
{
s_apartment.Dispose();
}
// ...
}
Finally, neither MessageLoopWorker nor MessageLoopApartment were designed to work with WinForms object created on different threads (which is almost never a good idea anyway). You can have as many MessageLoopWorker/MessageLoopApartment instances as you like, but once a WinForm object has been created on the thread of a particular MessageLoopWorker/MessageLoopApartment instance, it should further be accessed and properly destroyed on the same thread only.
I have code which calls an external lib synchronous operation, which can take a very long time to finish. I can't rewrite this lib, and there is not a method to stop the operation. Is there any solution to stop this task after some timeout?
I have tried this code, but it does not work not as I expected. It awaits until the calculation is not completed.
How can I solve this task?
private static async Task<ResultData> GetResultAsync(string fileName)
{
var timeoutSource = new CancellationTokenSource(new TimeSpan(0, 5, 0));
try
{
return await Task.Run(() =>
{
var result = ExternLib.Calculate(fileName);
if (result == null)
{
throw new CalculationException(fileName);
}
return result;
},
timeoutSource.Token
).ConfigureAwait(false);
}
catch (AggregateException e)
{
SomeCode(e);
}
catch (OperationCanceledException e)
{
SomeCode2(e);
}
catch (Exception e)
{
SomeCode3(e);
}
return await Task.FromResult<ResultData>(null).ConfigureAwait(false);
}
Create two tasks, one which does the work, and one which acts as a timer:
var workTask = Task.Run(() => // etc );
var timerTask = Task.Delay(TimeSpan.FromMinutes(10));
The wait for either task to complete:
var completedTask = Task.WaitAny(new[] { workTask, timerTask });
Then, if completedTask is the timer task, your timeout has expired, and you can take appropriate action: whether or not you can stop the long running task depends on how it's structured, but you do know you can stop waiting for it.
I have an infinite loop in a task. Under certain circumstances, this task throws an exception and terminates. Consider the following code snippet.
private async void Button_Click(object sender, RoutedEventArgs e)
{
try
{
int x = await FirstTask();
window.Title = "FirstTask completed with " + x.ToString();
}
catch (ArgumentException ex)
{
textbox.Text = ex.Message;
}
}
public async Task<int> FirstTask()
{
Task<int> secondTask;
int result;
secondTask = SecondTask();
textbox.Text = "Awaiting SecondTask result";
result = await secondTask;
textbox.Text = result;
secondTask.ContinueWith(async (Task t) =>
{
var thirdTask = ThirdTask();
thirdTask.ContinueWith(
async (m) =>
await Task.Run(() =>
{
throw thirdTask.Exception.InnerException;
}),
TaskContinuationOptions.OnlyOnFaulted);
}, TaskContinuationOptions.OnlyOnRanToCompletion);
return 5;
}
public async Task<int> SecondTask()
{
await Task.Delay(1500);
return 8;
}
public async Task ThirdTask()
{
while (true)
{
await Task.Delay(500);
throw new ArgumentException("thirdException");
}
}
My problems lies in the inability to propagate the exception thrown from ThirdTask to the Button_Click event. Obviously, awaiting it is not an options, since it is an ongoing infinite operation (this is only simplified to fail quickly). I have, however, no problem with awaiting the "short" task which re-throws the exception, if it is only triggered once the ThirdTask fails. Note that I'm not interested in the doings of the ThirdTask unless it fails, that is while I'm able to await the FirstTask in the event handler.
Experimenting showed that even the most simple example doesn't propagate the exception from the ContinueWith block.
private async void Button_Click(object sender, RoutedEventArgs e)
{
try
{
Task task = Task.Run(async () => { await Task.Delay(1000); });
task.ContinueWith( (t) => { throw new ArgumentException("test"); }, TaskContinuationOptions.OnlyOnRanToCompletion);
}
catch (ArgumentException ex)
{
textbox.Text = ex.Message;
}
}
So, how do I propagate an exception from ContinueWith to the calling context, given that the task that throws it has an infinite loop, which prevents me from awaiting it?
The problem I'm trying to solve is two-fold:
First, I need to initialize a resource (FirstTask), in order to do that, I first need to fetch it (SecondTask) and then to begin a process with it (ThirdTask), finally, the initialization of the resource (FirstTask) returns a value indicating the state of the resource, which doesn't depend on the process (ThirdTask). The process (ThirdTask) repeatedly invokes another task (in this case Task.Delay) and performs some work on it, but it can fail. In that case, it throws an exception which needs to be handled.
The second part is the general case of the second code example, of how to throw an exception from ContinueWith to be handled by the calling context.
given that the task that throws it has an infinite loop, which prevents me from awaiting it?
That in no way prevents you from awaiting it. The [easiest] way to handle the case that it throws an exception is specifically to await it.
You can simply implement the method as such:
public async Task FirstTask()
{
Task<int> secondTask = SecondTask();
textbox.Text = "Awaiting SecondTask result";
textbox.Text = await secondTask;
await ThirdTask();
}
If the click handler needs to both update a texbox with the results of the second operation and update the UI if the third fails, then you need to not wrap both of those operations in FirstTask and call them directly from the click handler:
private async void Button_Click(object sender, RoutedEventArgs e)
{
try
{
textbox.Text = "Awaiting SecondTask result";
int x = await SecondTask();
window.Title = "SecondTask completed with " + x.ToString();
await ThirdTask();
}
catch (ArgumentException ex)
{
textbox.Text = ex.Message;
}
}