So I have the following:
if (await Task.WhenAny(myLongRunningTask, Task.Delay(9000)) != myLongRunnnigTask && !myLongRunningTask.IsFaulted)
{
Console.WriteLine("TimedOut");
}
else
{
Console.WriteLine("Completed");
}
Seems to work fine when I complete my task; but if I never complete the long running task then this just hangs instead of timing out after 9 seconds. Even put in the faulted test to be sure.
(NOTE: Real code does more than just commandline write; but it never even gets into the scope; though I did try just commandline writing too... no change.)
Yet doing what looks to me to be exactly the same thing in LinqPad:
async void Main()
{
var Other = Task.Factory.StartNew(() => { Thread.Sleep(15000); });
if(await Task.WhenAny(Other, Task.Delay(4000)) != Other && !Other.IsFaulted) "TimedOut".Dump();
else "Completed".Dump();
Other = Task.Factory.StartNew(() => { Thread.Sleep(1000); });
if(await Task.WhenAny(Other, Task.Delay(4000)) != Other && !Other.IsFaulted) "TimedOut".Dump();
else "Completed".Dump();
}
That happily writes TimedOut then Completed.
The first code section is deep down in a pretty huge module. But I can't see what might side-effect it to this odd behaviour... What might I be missing?
NOTE on accepted answer:
The question here was what might be side-effecting this. #Douglas' answer indicates the side effect that was impacting my code. That does not necessarily fix the issue; just tells you where your problem lies. However he helpfully added a comment with a link to an article that does help you fix it.
This might happen if you're blocking on that async method from a synchronization context that executes continuations on the original thread, such as a WPF or WinForms UI. Try adding ConfigureAwait(false) and check whether that avoids the hanging:
var readyTask = await Task.WhenAny(myLongRunningTask, Task.Delay(9000)).ConfigureAwait(false);
if (readyTask != myLongRunnnigTask && !myLongRunningTask.IsFaulted)
{
Console.WriteLine("TimedOut");
}
else
{
Console.WriteLine("Completed");
}
But I can't see what might side-effect it to this odd behaviour...
Your longRunningTask is likely assigned the return value of a method like:
private static Task NewMethod()
{
Thread.Sleep(11000);
return Task.CompletedTask;
}
then later:
var myLongRunningTask = NewMethod();
Thus, by the time you reach the var readyTask = await line, the 11 second sleep ('long running task') has already occurred (since NewMethod is not asynchonous), and thus Task.WhenAny returns instantly (since longRunningTask is complete).
Related
I find the code snippet below has deadlock, although I already solved this problem by using read write lock, I still have no idea what exactly happens under the hood in Task.WhenAll that causes deadlock.
Problematic code:
public async static Task<Dictionary<string, Log4SerialPort>> AvailableLog4SerialPorts()
{
var ports = App.SerialPortService.GetAvailablePorts();
await Task.WhenAll(ports.Select(async port =>
{
if (!_availableLog4SerialPorts.ContainsKey(port.Path))
{
var log4Port = new Log4SerialPort(port);
var isValid = await log4Port.Verify();
if (isValid)
{
_availableLog4SerialPorts.Add(port.Path, log4Port);
}
}
}));
return _availableLog4SerialPorts;
}
By adding read write lock, problem solved:
public async static Task<Dictionary<string, Log4SerialPort>> AvailableLog4SerialPorts()
{
var ports = App.SerialPortService.GetAvailablePorts();
await Task.WhenAll(ports.Select(async port =>
{
rwl.AcquireReaderLock(VERIFY_TIMEOUT);
if (!_availableLog4SerialPorts.ContainsKey(port.Path))
{
rwl.ReleaseReaderLock();
var log4Port = new Log4SerialPort(port);
var isValid = await log4Port.Verify();
if (isValid)
{
rwl.AcquireWriterLock(VERIFY_TIMEOUT);
_availableLog4SerialPorts.Add(port.Path, log4Port);
rwl.ReleaseWriterLock();
}
}
}));
return _availableLog4SerialPorts;
}
_availableLog4SerialPorts is a static field.
log4Port.Verify() doesn't share any static resources, it just does some time-consuming tasks.
It seems Task.WhenAll will lock the static resources automatically, but not sure how it works and the detailed blocking reason in this case.
I made a small program to reproduce this problem, and it seems the reason why the program is blocked is as what #Michael Randall said, Dictionary in multi-threaded environment may cause unintended behaviour. Followings are the screenshot of the test. Without locks, the program will block at any arbitrary point during execution.
without locks
with locks (Sorry I still cannot embed images yet...)
Thanks for all your helps : )
I have the following:
public async Task<bool> SearchForUpdatesAsync()
{
return await TaskEx.Run(() =>
{
if (!ConnectionChecker.IsConnectionAvailable())
return false;
// Check for SSL and ignore it
ServicePointManager.ServerCertificateValidationCallback += delegate { return (true); };
var configurations = UpdateConfiguration.Download(UpdateConfigurationFileUri, Proxy);
var result = new UpdateResult(configurations, CurrentVersion,
IncludeAlpha, IncludeBeta);
if (!result.UpdatesFound)
return false;
_updateConfigurations = result.NewestConfigurations;
double updatePackageSize = 0;
foreach (var updateConfiguration in _updateConfigurations)
{
var newPackageSize = GetUpdatePackageSize(updateConfiguration.UpdatePackageUri);
if (newPackageSize == null)
throw new SizeCalculationException(_lp.PackageSizeCalculationExceptionText);
updatePackageSize += newPackageSize.Value;
_packageOperations.Add(new UpdateVersion(updateConfiguration.LiteralVersion),
updateConfiguration.Operations);
}
TotalSize = updatePackageSize;
return true;
});
}
As you can see I'm using Microsoft.Bcl.
Now in my other class I wrote this code in a normal void:
TaskEx.Run(async delegate
{
// ...
_updateAvailable = await _updateManager.SearchForUpdatesAsync();
MessageBox.Show("Test");
});
The problem I have is that it executes _updateAvailable = await _updateManager.SearchForUpdatesAsync(); and then it doesn't continue the thread, it just stops as if there is nothing after that call. Visual Studio also tells me this after a while: Thread ... exited with code 259, so something seems to be still alive.
I debugged through it to search for any exceptions that could maybe be swallowed, but nothing, everything works fine and it executes the return-statement.
And that is what I don't understand, I never see the MessageBox and/or no code beyond this line's being executed.
After I talked to some friends, they confirmed that this shouldn't be. Did I make a horrible mistake when implementing async-await?
Thanks in advance, that's actually all I can say about that, I got no more information, I appreciate any tips and help as far as it's possible.
The main issue that you're having is that you're unnecessarily wrapping your method in TaskEx.Run() and you are probably experiencing deadlock somewhere.
Your method signature is currently:
public async Task<bool> SearchForUpdatesAsync()
This means the following:
async --> Doesn't actually do anything, but provides a "heads up" that await might be called within this method and that this method can be used as a runnable Task.
Task --> This method returns a runnable task that can be run asynchronously on the threadpool
<bool> --> This method actually returns bool when awaited.
The await TaskEx.Run() is unnecessarily since this says run this method and then don't return until after a value is available. This is most likely causing a synchronization problem. Removing this construct will make your method work properly, however you'll notice that now you have no reason to even include the async operator or the Task<T> portion since the method is actually synchronous anyway. Usually you're only going to use async identifier on the method signature if you have methods that you are going to call await on them.
Instead you have two options.
Whenever you want to call SearchForUpdates() you can wrap this in a Task<bool>.Run() to run it asynchronously (or the Bcl equivalent)
Since you are using WinForms you might be better off using a BackgroundWorker and just calling this method within it.
Regarding using the async-await pattern I think that this is a great article to use to make sure you're following best practices: https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
The best practice is to have async all the way through your layers, and then call await or less desirably .Wait() / .Result at the final use site.
Also, try to keep your UI calls separate from the backend work, since you can run into synchronicity/thread-context issue.
public class WinFormsCode
{
private async Task WinsFormCodeBehindMethodAsync()
{
var updatesAvailable = await _updateManager.SearchForUpdatesAsync();
MessageBox.Show("Updates Available: " + updatesAvailable.ToString());
}
private void WinsFormCodeBehindMethodSync()
{
var updatesAvailable = _updateManager.SearchForUpdatesAsync().Result;
MessageBox.Show("Updates Available: " + updatesAvailable.ToString());
}
}
public class UpdateManager
{
public async Task<bool> SearchForUpdatesAsync()
{
return true;
}
}
I have the following code:
var tasks = await taskSeedSource
.Select(taskSeed => GetPendingOrRunningTask(taskSeed, createTask, onFailed, onSuccess, sem))
.ToList()
.ToTask();
if (tasks.Count == 0)
{
return;
}
if (tasks.Contains(null))
{
tasks = tasks.Where(t => t != null).ToArray();
if (tasks.Count == 0)
{
return;
}
}
await Task.WhenAll(tasks);
Where taskSeedSource is a Reactive Observable. It could be that this code have many problems, but I see at least two:
I am collecting tasks whereas I could do without it.
Somehow, the returned tasks list may contain nulls, even though GetPendingOrRunningTask is an async method and hence never returns null. I failed to understand why it happens, so I had to defend against it without understanding the cause of the problem.
I would like to use the AsyncCountdownEvent from the AsyncEx framework instead of collecting the tasks and then awaiting on them.
So, I can pass the countdown event to GetPendingOrRunningTask which will increment it immediately and signal before returning after awaiting for the completion of its internal logic. However, I do not understand how to integrate the countdown event into the monad (that is the Reactive jargon, isn't it?).
What is the right way to do it?
EDIT
Guys, let us forget about the mysterious nulls in the returned list. Suppose everything is green and the code is
var tasks = await taskSeedSource
.Select(taskSeed => GetPendingOrRunningTask(taskSeed, ...))
.ToList()
.ToTask();
await Task.WhenAll(tasks);
Now the question is how do I do it with the countdown event? So, suppose I have:
var c = new AsyncCountdownEvent(1);
and
async Task GetPendingOrRunningTask<T>(AsyncCountdownEvent c, T taskSeed, ...)
{
c.AddCount();
try
{
await ....
}
catch (Exception exc)
{
// The exception is handled
}
c.Signal();
}
My problem is that I no longer need the returned task. These tasks where collected and awaited to get the moment when all the work items are over, but now the countdown event can be used to indicate when the work is over.
My problem is that I am not sure how to integrate it into the Reactive chain. Essentially, the GetPendingOrRunningTask can be async void. And here I am stuck.
EDIT 2
Strange appearance of a null entry in the list of tasks
#Servy is correct that you need to solve the null Task problem at the source. Nobody wants to answer a question about how to workaround a problem that violates the contracts of a method that you've defined yourself and yet haven't provided the source for examination.
As for the issue about collecting tasks, it's easy to avoid with Merge if your method returns a generic Task<T>:
await taskSeedSource
.Select(taskSeed => GetPendingOrRunningTask(taskSeed, createTask, onFailed, onSuccess, sem))
.Where(task => task != null) // According to you, this shouldn't be necessary.
.Merge();
However, unfortunately there's no official Merge overload for the non-generic Task but that's easy enough to define:
public static IObservable<Unit> Merge(this IObservable<Task> sources)
{
return sources.Select(async source =>
{
await source.ConfigureAwait(false);
return Unit.Default;
})
.Merge();
}
I have a very strange problem. My WebClient.DownloadDataCompleted doesn't fire most of the time.
I am using this class:
public class ParallelFilesDownloader
{
public Task DownloadFilesAsync(IEnumerable<Tuple<Uri, Stream>> files, CancellationToken cancellationToken)
{
var localFiles = files.ToArray();
var tcs = new TaskCompletionSource<object>();
var clients = new List<WebClient>();
cancellationToken.Register(
() =>
{
// Break point here
foreach (var wc in clients.Where(x => x != null))
wc.CancelAsync();
});
var syncRoot = new object();
var count = 0;
foreach (var file in localFiles)
{
var client = new WebClient();
client.DownloadDataCompleted += (s, args) =>
{
// Break point here
if (args.Cancelled)
tcs.TrySetCanceled();
else if (args.Error != null)
tcs.TrySetException(args.Error);
else
{
var stream = (Stream)args.UserState;
stream.Write(args.Result, 0, args.Result.Length);
lock (syncRoot)
{
count++;
if (count == localFiles.Length)
tcs.TrySetResult(null);
}
}
};
clients.Add(client);
client.DownloadDataAsync(file.Item1, file.Item2);
}
return tcs.Task;
}
}
And when I am calling DownloadFilesAsync in LINQPad in isolation, DownloadDataCompleted is called after half a second or so, as expected.
However, in my real application, it simply doesn't fire and the code that waits for it to finish simply is stuck. I have two break points as indicated by the comments. None of them is hit.
Ah, but sometimes, it does fire. Same URL, same code, just a new debug session. No pattern at all.
I checked the available threads from the thread pool: workerThreads > 30k, completionPortThreads = 999.
I added a sleep of 10 seconds before the return and checked after the sleep that my web clients haven't been garbage collected and that my event handler is still attached.
Now, I ran out of ideas to trouble shoot this.
What else could cause this strange behaviour?
From the comments:
Somewhere later, there is a Task.WaitAll which waits for this and other tasks. However, (1) I fail to see why this would affect the async download - please elaborate - and (2) the problem doesn't disappear, when I add the sleep and as such, Task.WaitAll will not be called
It seems that you have a deadlock caused by Task.WaitAll. I can explain it throughly here:
When you await an async method that returns a Task or a Task<T>, there is an implicit capture of the SynchronizationContext by the TaskAwaitable being generated by the Task.GetAwaiter method.
Once that sync context is in place and the async method call completes, the TaskAwaitable attempts to marshal the continuation (which is basically the rest of the method calls after the first await keyword) onto the SynchronizationContext (using SynchronizationContext.Post) which was previously captured. If the calling thread is blocked, waiting on that same method to finish, you have a deadlock.
When you call Task.WaitAll, you block until all Tasks are complete, this will make marshaling back to the original context impossible, and basically deadlock.
Instead of using Task.WaitAll, use await Task.WhenAll.
Based on the comments, not an ideal answer but you can temporarily change the sync context before and after the foreach:
var syncContext = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(null);
foreach (var file in localFiles)
{
...
}
SynchronizationContext.SetSynchronizationContext(syncContext);
I'm hoping there is a simple answer here, and this is probably due to my misunderstanding of asynchronous operations...
I have a method that can be started manually or can autostart when the program loads. The async method works perfectly when invoked manually (on button press). However, when autoloaded the method just seems to skip the main "await" part of the method without performing any work, and skips straight to the end.
The whole process starts in this method:
private void StartBatch()
{
var batchSize = (int)BatchSizeSlider.Value;
if (_config.AutoStart)
{
ExecutionLogAddItem(string.Format("Auto batch processing started (batch size: {0})", batchSize.ToString()));
Task.Factory.StartNew(async () =>
{
await BatchTransfer(batchSize);
CompleteBatch();
});
}
else
{
var start = ConfirmStartBatch();
var doBatch = start.ContinueWith(async (continuation) =>
{
//start task
if (start.Result == true)
{
ExecutionLogAddItem("Batch processing started.");
ExecutionLogAddItem(string.Format("Batch size set at {0}", batchSize.ToString()));
await BatchTransfer(batchSize).ContinueWith((x) => CompleteBatch());
}
else
{
ExecutionLogAddItem("Batch processing aborted.");
}
});
}
}
If _config.AutoStart is true, the BatchTransfer method doesn't seem to do anything, instead the program skips straight to the CompleteBatch() method. If invoked manually everything works as expected.
The strange thing is, if I set a breakpoint on await BatchTransfer(batchSize) in the autostarted method, I can step through the code and the batch transfers take place. So when debugging it works, when not debugging it doesn't. Please help!
It is because -
Task.Factory.StartNew(async () =>
{
await BatchTransfer(batchSize);
CompleteBatch();
});
You are waiting for the inner task to complete with await but Task.Factory.StartNew(async () => itself is an asynchronous task and is not awaited. You should also wait for Task.Factory.StartNew(async () => like this -
await Task.Factory.StartNew(async () =>
When you are debugging, the separate thread that is calling inner task is held and you can see the execution but when running normally the background is still working, but you cannot see it since you didn't wait for the Task.Factory.StartNew(async () =>.
If you check the thread pool and thread id, I am sure you will see that they are different when debugging.
This blog might help you understand the situation - http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx
In order to use await you have to make your method async and call it without Task.Factory.StartNew. One more thing, instead of void make return type as Task of your method because void async are fire and forget. You will not able to track them.
private async Task StartBatch()
{
await BatchTransfer(batchSize);
CompleteBatch();
}
Check this link. It have very basic demonstration of async and it is very helpful in understanding how asynchrony works. Six Essential Tips For Async - Introduction. It includes six tips which are very essential. I recommend you go through all of them but to understand current question situation you can go through Tip 1 whose title is Async void is for top-level event-handlers only.