Find deadlock in Task.WhenAll - c#

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 : )

Related

Why sequential call of AsyncLock within same (UI) thread doesn't work same way as for different threads (like via Task.Run)?

Partially, this question has a bit of similarity with this one, but as another one is not properly asked (and not fully asked) I am trying to ask it in general, so this question can not be considered as a duplication.
The question is about understanding of how AsyncLock actually works. (In this context I am referring to Neosmart.AsyncLock library, however, I consider it uses common approach in AsyncLock implementation).
So. For instance, we have a main thread (let it be a UI-thread):
static void Main(string[] args)
{
Console.WriteLine("Press Esc for exit");
var lck = new AsyncLock();
var doJob = new Action(async () =>
{
using (await lck.LockAsync())
{
// long lasting job
Console.WriteLine("+++ Job starts");
await Task.Delay(TimeSpan.FromSeconds(10));
Console.WriteLine("--- Job finished");
}
});
while (Console.ReadKey().Key != ConsoleKey.Escape)
{
doJob();
}
}
so, sequental pressing of Enter starts doJobevery time without waiting until previous job finished.
However, when we change it to:
Task.Run(() =>
{
doJob();
});
... everything works like a charm, and no new jobs is run until previous finished.
That's clear that async logic is far different than classic lock(_myLock) and can't be comparable directly, however, still, why the first approach doesn't work that way when the second call of LockAsync would "lock" (again, in async context) the "long lasting job" to start until previous finished.
There is actually a practical request of why I need that code to work this way, (and real question is how I can achieve that with await LockAsync?):
For example, in my app (for instance, my mobile app), on very launch there is some data I am starting pre-loading (this is a common service which needs that data to keep in cache for further use), then, when the UI is started, a particular page requests the same data for the UI to appear and asks the same service to load the same data. So, without any custom logic that service would start two long lasting jobs to retrieve the same pack of data. Instead, I want my UI to receive the data from the cache right the data pre-loading finished.
Like that (an abstract possible scenario):
class MyApp
{
string[] _cache = null;
AsyncLock _lock = new AsyncLock();
async Task<IEnumerable<string>> LoadData()
{
using (await _lock.LockAsync())
{
if (_cache == null)
{
await Task.Delay(TimeSpan.FromSeconds(10));
_cache = new[] {"one", "two", "three"};
}
return _cache;
}
}
void OnAppLaunch()
{
LoadData();
}
async void OnMyCustomEvent()
{
var data = await LoadData();
// to do something else with the data
}
}
the problem would be solved if I would change it to Task.Run(async () => { var data = await LoadData(); }) but it doesn't look like quite clean and nice approach.
As Matthew points out in the comments, AsyncLock is reentrant, meaning that if the same thread attempts to take the lock a second time, it recognizes that and allows it to continue. The author of AsyncLock wrote a lengthy article about how reentrance was really the reason he wrote it: AsyncLock: an async/await-friendly locking library for C# and .NET
It's not a bug; it's a feature.™
After the "Update 5/25/2017" heading, there are code examples demonstrating exactly what you are experiencing here and showing how it is a feature.
Reasons to want reentrance are:
If you are just concerned with multiple threads touching the same variable (preventing race conditions), then there is simply no reason to block a thread that already has the lock.
It makes recursive functions that use locks easier to write because you don't need to test if you already have the lock. A lack of reentrance support + sloppy recursive coding = deadlock.
If you really want it to not be reentrant, you can use what he says was not appropriate for reentrance: SemaphoreSlim:
var lck = new SemaphoreSlim(1);
var doJob = new Action(async () => {
await lck.WaitAsync();
try {
// long lasting job
Console.WriteLine("+++ Job starts");
await Task.Delay(TimeSpan.FromSeconds(2));
Console.WriteLine("--- Job finished");
} finally {
lck.Release();
}
});

Async Change Streams in MongoDB

I want to listen to a change stream for a collection, without blocking the thread.
In the code below the ForEachAsync will block forever, processing changes as they occur.
using (var cursor = await collection.WatchAsync())
{
await cursor.ForEachAsync(change =>
{
// process change event
});
}
I have tried removing "await" and storing the task in a variable instead, but no changes will be processed before i actually either await or .Wait() the task later.
I would expect that even though I don't await the task, the events would still be processed.
What can I do, so my entire program doesn't block to listen for changes?
I am considering wrapping the functionality in a new thread, but is that really necessary?
I don't have enough reputation to comment (yet) so my feedback in the form of an answer:
You should be working with events (listeners, handlers) instead of await/async in this situation.
It's difficult to elaborate on this without having more information on what you're trying to accomplish.
So, I figured out that the following works...
static void Main(string[] args)
{
Task watchTask = WatchCollection();
// Do other stuff here, while watching...
}
private static async Task WatchCollection()
{
using (var cursor = collection.Watch())
{
await cursor.ForEachAsync(change =>
{
// process change event
});
}
}
While I was attempting to do it like this, which doesn't work:
static void Main(string[] args)
{
using (var cursor = collection.Watch())
{
Task watchTask cursor.ForEachAsync(change =>
{
// process change event
});
}
// Do other stuff here, while watching
}
So, the actual ForEachAsync task is awaited, while the outer Task which wraps the entire functionality is not awaited... I am either too tired or not familiar enough with Tasks to give a good explanation of why one works and the other doesn't.

Why does my delay task not trigger the Task.WaitAny()

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).

What causes a Task to complete?

I'm trying to find out how to use WhenAll to let two methods run at once, and once they both finish, collect the results without blocking by using .Result
I have this little console app test:
using System.Diagnostics;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class Program
{
public static void Main(string[] args)
{
var run = TaskRunner();
Debug.WriteLine(run);
if (run.IsCompleted)
{
Debug.WriteLine("this worked!");
} else
{
Debug.WriteLine("this failed!");
}
}
public static async Task<string> TaskRunner()
{
var taskOne = OneAsync();
var taskTwo = TwoAsync();
var tasks = await Task.WhenAll(taskOne, taskTwo);
var retval = tasks[0] + tasks[1];
return retval;
}
public static Task<string> OneAsync()
{
return Task.Run(() =>
{
return "test1";
});
}
public static Task<string> TwoAsync()
{
return Task.Run(() =>
{
return "test2";
});
}
}
}
This currently prints this worked! to my Output window... However, if I comment out Debug.WriteLine(run); it prints this failed!... Why does the Task complete simply by being logged to the output window?
I'm trying to understand a huge problem in a complex piece of code and this little test is my MCVE to hopefully shed some light on what is happening behind the scenes.
This happens just by pure chance. The way you are starting your task is with Task.Run. This essentially creates a new thread on which the (synchronous) action is executed. It returns a task for the completion of that thread.
So OneAsync and TwoAsync will each spawn a new thread that then immediately returns a string. This will happen very quickly but there’s still some overhead for creating those threads which means that it won’t be instantaneous.
TaskRunner then calls both those methods (spawning the threads), and then asynchronously waits for both threads to finish. Since the threads are not completely instantly, this TaskRunner method also won’t complete instantly.
Now, in your main, you are starting the asynchronous TaskRunner, which we figured will take “a very short moment”. You do not await the task, so the execution continues immediately. Debug.WriteLine is executed to print something (it probably doesn’t really matter that it’s the task in question that is being printed), and then you are checking the state of the task.
Since printing stuff is relatively slow (compared to other operations), this is probably the reason why the tasks ends up being completed. And when you remove the printing, the if is just reached too quickly for the task to finish.
As you likely noticed, working like that with asynchronous tasks does not appear to be a good idea. That’s why you should always await the task when you depend on its result.
// note the *async* here; async main methods are supported with C# 7.1
public static async void Main(string[] args)
{
var run = TaskRunner();
// await the task
await run;
if (run.IsCompleted)
{
Debug.WriteLine("this worked!");
}
else
{
Debug.WriteLine("this failed!");
}
}

Await stops execution of thread and never continues

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;
}
}

Categories