Code execution blocked with Factory.StartNew - c#

Factory.StartNew leads to code execution blockage when I don't used Thread.Sleep(20);
I tried the following:
Thread.Sleep() - This works with Factory.StartNew & produces desirable result
Task.Delay(20) - This doesn't work with Factory.StartNew
Task<bool>.Run - Using this instead of Factory.StartNew doesn't make any difference
The code:
private async Task<bool> GetStatus()
{
var MyTask = Task<bool>.Factory.StartNew( () =>
//var MyTask = Task<bool>.Run( () => // Using Task.Run doesn't make any
//difference
{
while (true)
{
if (EventStatus.ToString() == "Rejected")
break;
if (EventStatus.ToString() == "Error")
break;
Thread.Sleep(20);// This gives the desirable result.Removing it
//causes application to hang
//Task.Delay(20);// This line doesn't make any difference
}
return true;
});
MyTask.Wait();
return await MyTask;
}
If I use Task.Factory.StartNew without using Thread.Sleep(20) code gets stuck in endless loop.
How can I improve code and get it to work without using Thread.Sleep(20) ?
I tried Task.Factory.StartNew specifying TaskScheduler but that caused code to hang too.

First, don't use StartNew. It's dangerous. Use Task.Run instead.
Second, the reason you're seeing and endless loop is that Task.Delay just starts a timer and returns a task that completes when that timer fires. If you want the code to actually wait for the timer, then you need to await that task. Also, EventStatus is being accessed from multiple threads without protection, which is not good. You'll need to add a lock to fix this permanently:
private async Task<bool> GetStatus()
{
var task = Task.Run(async () =>
{
while (true)
{
// TODO: add lock for EventStatus
if (EventStatus.ToString() == "Rejected")
break;
if (EventStatus.ToString() == "Error")
break;
await Task.Delay(20);
}
return true;
});
return await task;
}
As a final note, I would get rid of this entirely. Instead of polling for EventStatus to change, make it an actual "signal". E.g., assuming EventStatus is set once, then a TaskCompletionSource<bool> would work fine.

Related

Why does user interface still freeze?

I'm trying to prevent freezing application interface at waiting moment, so I code this function, but it doesn't work.
Where is the mistake, and how can I solve this?
async void buttonBlocking()
{
await Task.Run(() =>
{
if (irTryCounter % 3 == 0)
{
this.Dispatcher.Invoke(() =>
{
grdLogin.IsEnabled = false;
Thread.Sleep(10000);
grdLogin.IsEnabled = true;
});
}
});
}
If your buttonBlocking is invoked from UI thread, then you can simplify your code:
async void buttonBlocking()
{
if (irTryCounter % 3 == 0)
{
grdLogin.IsEnabled = false;
await Task.Delay(10000);
grdLogin.IsEnabled = true;
}
}
This way it won't block your UI
The mistake, as pointed by Matthew Watson in a comment, is that the Dispatcher.Invoke() will run the code on the UI thread, so the Thread.Sleep will be blocking the UI thread.
Now let's see how this problem can be fixed. I am assuming that your code is an event handler, and you want this handler to run asynchronously. This is the only valid scenario for using an async void method. In any other case you should use async Task.
private async void Button1_Click(object sender, RoutedEventArgs e)
{
if (irTryCounter % 3 == 0)
{
grdLogin.IsEnabled = false;
await Task.Run(() =>
{
// Here you can run any code that takes a long time to complete
// Any interaction with UI controls is forbidden here
// This code will run on the thread-pool, not on the UI thread
Thread.Sleep(10000);
});
grdLogin.IsEnabled = true;
}
}
In case the long-running operation returns a result that needs to be passed to the UI thread, use the Task.Run overload that returns a Task<TResult>:
int result = await Task.Run(() =>
{
Thread.Sleep(10000);
return 13;
});
// We are back on the UI thread, and the result is available for presentation
I am assuming that the Thread.Sleep(10000) is a placeholder for an actual synchronous operation that takes a long time to complete. It would be even better if this operation can be performed asynchronously, because it would not require consuming a ThreadPool thread for the whole duration of the operation. As an example, a delay can be performed asynchronously by using the Task.Delay method:
await Task.Run(async () =>
{
await Task.Delay(10000);
});
In this case the Task.Run wrapper may seem redundant, but actually it's not. Wrapping your asynchronous code in a Task.Run protects your application from badly behaving asynchronous APIs that block the current thread. The overhead of including the wrapper is minuscule, and should have no noticeable effect in a WinForms/WPF application. The exception is ASP.NET applications, where Task.Runing is inadvisable.

Understanding async/await vs Wait in C# with "ContinueWith" behavior

One method is a standard async method, like this one :
private static async Task AutoRetryHandlerAsync_Worker(Func<Task<bool>> taskToRun,...)
I have tested two implementations, one that use await and the other uses .Wait()
The two implementations are not equal at all because the same tests are failing with the await version but not the Wait() one.
The goal of this method is to "execute a Task returned by the input function, and retry by executing the same function until it works" (with limitations to stop automatically if a certain number of tries is reached).
This works:
private static async Task AutoRetryHandlerAsync_Worker(Func<Task<bool>> taskToRun,...)
{
try {
await taskToRun();
}
catch(Exception)
{
// Execute later, and wait the result to complete
await Task.Delay(currentDelayMs).ContinueWith(t =>
{
// Wait for the recursive call to complete
AutoRetryHandlerAsync_Worker(taskToRun).Wait();
});
// Stop
return;
}
}
And this (with async t => and the usage of await instead of t => and the usage of .Wait() doesn't work at all because the result of the recursive call is not awaited before the final return; is executed :
private static async Task AutoRetryHandlerAsync_Worker(Func<Task<bool>> taskToRun,...)
{
try {
await taskToRun();
}
catch(Exception)
{
// Execute later, and wait the result to complete
await Task.Delay(currentDelayMs).ContinueWith(async t =>
{
// Wait for the recursive call to complete
await AutoRetryHandlerAsync_Worker(taskToRun);
});
// Stop
return;
}
}
I'm trying to understand why this simple change does change everything, when it's supposed to do the exact same thing : waiting the ContinueWith completion.
If I extract the task ran by the ContinueWith method, I do see the state of the ContinueWith function passing to "ranToCompletion" before the return of the inner await completes.
Why? Isn't it supposed to be awaited?
Concrete testable behaviour
public static void Main(string[] args)
{
long o = 0;
Task.Run(async () =>
{
// #1 await
await Task.Delay(1000).ContinueWith(async t =>
{
// #2 await
await Task.Delay(1000).ContinueWith(t2 => {
o = 10;
});
});
var hello = o;
});
Task.Delay(10000).Wait();
}
Why does var hello = o; is reached before o=10?
Isn't the #1 await supposed to hang on before the execution can continue?
The lambda syntax obscures the fact that you ContinueWith(async void ...).
async void methods are not awaited and any errors they throw will go unobserved.
And to your base question, retrying from within a catch is not a recommended practice anyway. Too much going on, catch blocks should be simple. And bluntly retrying for all exception types is also very suspect. You ought to have an idea what errors could warrant a retry, and let the rest pass.
Go for simplicity and readability:
while (count++ < N)
{
try
{
MainAction();
break;
}
catch(MoreSpecificException ex) { /* Log or Ignore */ }
Delay();
}

Asyc method using await Task.Run() never "completes"

I have a method that is defined as
public async Task SomeAsyncMethod()
{
DoSomeStuff();
await Task.Run(() => {
DoSomeSyncStuff();
DoSomeOtherSyncStuff();
});
var someDebugVariable = "someDebugValue";
}
The method itself does exactly what it is supposed to do and everything runs fine. Yet ... it looks like the "outer" async Task never completes.
Example: When I call it like this
public void CallerMethod()
{
Task t = SomeAsyncMethod();
t.Wait();
}
the t.Wait() never completes. Furthermore: if I place a breakpoint at the assignment of someDebugVariable it never gets hit.
I might add that DoSomeSyncStuff and DoSomeOtherSyncStuff really do what they are supposed to and debugging through them tells me that they both complete.
To prove my point I modified my method like this, and the results are still the same.
public async Task SomeAsyncMethod()
{
DoSomeStuff();
await Task.Run(() => {
/*
DoSomeSyncStuff();
DoSomeOtherSyncStuff();
*/
var a = 2; var b = 3; var c = a + b;
});
var someDebugVariable = "someDebugValue";
}
EDIT
I have tried removing everything but the await Task.Run and it does not change anything. It still does not complete.
The application is a WPF application. The caller thread is the UI thread.
What am I missing here?
The t.Wait() call is causing a deadlock, and also makes the async call entirely pointless. I believe if you change the code to
await Task.Run(() => {
// ...
}).ConfigureAwait(false);
You can fix the deadlock and let the code proceed, but you should really get rid of the t.Wait() call. Anything that needs to be done with the results of the sync function calls should be done after the awaited task, not after the call of the async function.
More in depth:
task.Wait() will block all execution on the main thread while the task is running. When the await task completes, it tries to marshall back to the main thread, but the main thread is blocked! Since A is waiting for B, and B is waiting for A, you get a deadlock.
See: http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

Parallel.ForEach using Thread.Sleep equivalent

So here's the situation: I need to make a call to a web site that starts a search. This search continues for an unknown amount of time, and the only way I know if the search has finished is by periodically querying the website to see if there's a "Download Data" link somewhere on it (it uses some strange ajax call on a javascript timer to check the backend and update the page, I think).
So here's the trick: I have hundreds of items I need to search for, one at a time. So I have some code that looks a little bit like this:
var items = getItems();
Parallel.ForEach(items, item =>
{
startSearch(item);
var finished = isSearchFinished(item);
while(finished == false)
{
finished = isSearchFinished(item); //<--- How do I delay this action 30 Secs?
}
downloadData(item);
}
Now, obviously this isn't the real code, because there could be things that cause isSearchFinished to always be false.
Obvious infinite loop danger aside, how would I correctly keep isSearchFinished() from calling over and over and over, but instead call every, say, 30 seconds or 1 minute?
I know Thread.Sleep() isn't the right solution, and I think the solution might be accomplished by using Threading.Timer() but I'm not very familiar with it, and there are so many threading options that I'm just not sure which to use.
It's quite easy to implement with tasks and async/await, as noted by #KevinS in the comments:
async Task<ItemData> ProcessItemAsync(Item item)
{
while (true)
{
if (await isSearchFinishedAsync(item))
break;
await Task.Delay(30 * 1000);
}
return await downloadDataAsync(item);
}
// ...
var items = getItems();
var tasks = items.Select(i => ProcessItemAsync(i)).ToArray();
await Task.WhenAll(tasks);
var data = tasks.Select(t = > t.Result);
This way, you don't block ThreadPool threads in vain for what is mostly a bunch of I/O-bound network operations. If you're not familiar with async/await, the async-await tag wiki might be a good place to start.
I assume you can convert your synchronous methods isSearchFinished and downloadData to asynchronous versions using something like HttpClient for non-blocking HTTP request and returning a Task<>. If you are unable to do so, you still can simply wrap them with Task.Run, as await Task.Run(() => isSearchFinished(item)) and await Task.Run(() => downloadData(item)). Normally this is not recommended, but as you have hundreds of items, it sill would give you a much better level of concurrency than with Parallel.ForEach in this case, because you won't be blocking pool threads for 30s, thanks to asynchronous Task.Delay.
You can also write a generic function using TaskCompletionSource and Threading.Timer to return a Task that becomes complete once a specified retry function succeeds.
public static Task RetryAsync(Func<bool> retryFunc, TimeSpan retryInterval)
{
return RetryAsync(retryFunc, retryInterval, CancellationToken.None);
}
public static Task RetryAsync(Func<bool> retryFunc, TimeSpan retryInterval, CancellationToken cancellationToken)
{
var tcs = new TaskCompletionSource<object>();
cancellationToken.Register(() => tcs.TrySetCanceled());
var timer = new Timer((state) =>
{
var taskCompletionSource = (TaskCompletionSource<object>) state;
try
{
if (retryFunc())
{
taskCompletionSource.TrySetResult(null);
}
}
catch (Exception ex)
{
taskCompletionSource.TrySetException(ex);
}
}, tcs, TimeSpan.FromMilliseconds(0), retryInterval);
// Once the task is complete, dispose of the timer so it doesn't keep firing. Also captures the timer
// in a closure so it does not get disposed.
tcs.Task.ContinueWith(t => timer.Dispose(),
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
return tcs.Task;
}
You can then use RetryAsync like this:
var searchTasks = new List<Task>();
searchTasks.AddRange(items.Select(
downloadItem => RetryAsync( () => isSearchFinished(downloadItem), TimeSpan.FromSeconds(2)) // retry timout
.ContinueWith(t => downloadData(downloadItem),
CancellationToken.None,
TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.Default)));
await Task.WhenAll(searchTasks.ToArray());
The ContinueWith part specifies what you do once the task has completed successfully. In this case it will run your downloadData method on a thread pool thread because we specified TaskScheduler.Default and the continuation will only execute if the task ran to completion, i.e. it was not canceled and no exception was thrown.

Calling TaskCompletionSource.SetResult in a non blocking manner

I've discovered that TaskCompletionSource.SetResult(); invokes the code awaiting the task before returning. In my case that result in a deadlock.
This is a simplified version that is started in an ordinary Thread
void ReceiverRun()
while (true)
{
var msg = ReadNextMessage();
TaskCompletionSource<Response> task = requests[msg.RequestID];
if(msg.Error == null)
task.SetResult(msg);
else
task.SetException(new Exception(msg.Error));
}
}
The "async" part of the code looks something like this.
await SendAwaitResponse("first message");
SendAwaitResponse("second message").Wait();
The Wait is actually nested inside non-async calls.
The SendAwaitResponse(simplified)
public static Task<Response> SendAwaitResponse(string msg)
{
var t = new TaskCompletionSource<Response>();
requests.Add(GetID(msg), t);
stream.Write(msg);
return t.Task;
}
My assumption was that the second SendAwaitResponse would execute in a ThreadPool thread but it continues in the thread created for ReceiverRun.
Is there anyway to set the result of a task without continuing its awaited code?
The application is a console application.
I've discovered that TaskCompletionSource.SetResult(); invokes the code awaiting the task before returning. In my case that result in a deadlock.
Yes, I have a blog post documenting this (AFAIK it's not documented on MSDN). The deadlock happens because of two things:
There's a mixture of async and blocking code (i.e., an async method is calling Wait).
Task continuations are scheduled using TaskContinuationOptions.ExecuteSynchronously.
I recommend starting with the simplest possible solution: removing the first thing (1). I.e., don't mix async and Wait calls:
await SendAwaitResponse("first message");
SendAwaitResponse("second message").Wait();
Instead, use await consistently:
await SendAwaitResponse("first message");
await SendAwaitResponse("second message");
If you need to, you can Wait at an alternative point further up the call stack (not in an async method).
That's my most-recommended solution. However, if you want to try removing the second thing (2), you can do a couple of tricks: either wrap the SetResult in a Task.Run to force it onto a separate thread (my AsyncEx library has *WithBackgroundContinuations extension methods that do exactly this), or give your thread an actual context (such as my AsyncContext type) and specify ConfigureAwait(false), which will cause the continuation to ignore the ExecuteSynchronously flag.
But those solutions are much more complex than just separating the async and blocking code.
As a side note, take a look at TPL Dataflow; it sounds like you may find it useful.
As your app is a console app, it runs on the default synchronization context, where the await continuation callback will be called on the same thread the awaiting task has become completed on. If you want to switch threads after await SendAwaitResponse, you can do so with await Task.Yield():
await SendAwaitResponse("first message");
await Task.Yield();
// will be continued on a pool thread
// ...
SendAwaitResponse("second message").Wait(); // so no deadlock
You could further improve this by storing Thread.CurrentThread.ManagedThreadId inside Task.Result and comparing it to the current thread's id after the await. If you're still on the same thread, do await Task.Yield().
While I understand that SendAwaitResponse is a simplified version of your actual code, it's still completely synchronous inside (the way you showed it in your question). Why would you expect any thread switch in there?
Anyway, you probably should redesign your logic the way it doesn't make assumptions about what thread you are currently on. Avoid mixing await and Task.Wait() and make all of your code asynchronous. Usually, it's possible to stick with just one Wait() somewhere on the top level (e.g. inside Main).
[EDITED] Calling task.SetResult(msg) from ReceiverRun actually transfers the control flow to the point where you await on the task - without a thread switch, because of the default synchronization context's behavior. So, your code which does the actual message processing is taking over the ReceiverRun thread. Eventually, SendAwaitResponse("second message").Wait() is called on the same thread, causing the deadlock.
Below is a console app code, modeled after your sample. It uses await Task.Yield() inside ProcessAsync to schedule the continuation on a separate thread, so the control flow returns to ReceiverRun and there's no deadlock.
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication
{
class Program
{
class Worker
{
public struct Response
{
public string message;
public int threadId;
}
CancellationToken _token;
readonly ConcurrentQueue<string> _messages = new ConcurrentQueue<string>();
readonly ConcurrentDictionary<string, TaskCompletionSource<Response>> _requests = new ConcurrentDictionary<string, TaskCompletionSource<Response>>();
public Worker(CancellationToken token)
{
_token = token;
}
string ReadNextMessage()
{
// using Thread.Sleep(100) for test purposes here,
// should be using ManualResetEvent (or similar synchronization primitive),
// depending on how messages arrive
string message;
while (!_messages.TryDequeue(out message))
{
Thread.Sleep(100);
_token.ThrowIfCancellationRequested();
}
return message;
}
public void ReceiverRun()
{
LogThread("Enter ReceiverRun");
while (true)
{
var msg = ReadNextMessage();
LogThread("ReadNextMessage: " + msg);
var tcs = _requests[msg];
tcs.SetResult(new Response { message = msg, threadId = Thread.CurrentThread.ManagedThreadId });
_token.ThrowIfCancellationRequested(); // this is how we terminate the loop
}
}
Task<Response> SendAwaitResponse(string msg)
{
LogThread("SendAwaitResponse: " + msg);
var tcs = new TaskCompletionSource<Response>();
_requests.TryAdd(msg, tcs);
_messages.Enqueue(msg);
return tcs.Task;
}
public async Task ProcessAsync()
{
LogThread("Enter Worker.ProcessAsync");
var task1 = SendAwaitResponse("first message");
await task1;
LogThread("result1: " + task1.Result.message);
// avoid deadlock for task2.Wait() with Task.Yield()
// comment this out and task2.Wait() will dead-lock
if (task1.Result.threadId == Thread.CurrentThread.ManagedThreadId)
await Task.Yield();
var task2 = SendAwaitResponse("second message");
task2.Wait();
LogThread("result2: " + task2.Result.message);
var task3 = SendAwaitResponse("third message");
// still on the same thread as with result 2, no deadlock for task3.Wait()
task3.Wait();
LogThread("result3: " + task3.Result.message);
var task4 = SendAwaitResponse("fourth message");
await task4;
LogThread("result4: " + task4.Result.message);
// avoid deadlock for task5.Wait() with Task.Yield()
// comment this out and task5.Wait() will dead-lock
if (task4.Result.threadId == Thread.CurrentThread.ManagedThreadId)
await Task.Yield();
var task5 = SendAwaitResponse("fifth message");
task5.Wait();
LogThread("result5: " + task5.Result.message);
LogThread("Leave Worker.ProcessAsync");
}
public static void LogThread(string message)
{
Console.WriteLine("{0}, thread: {1}", message, Thread.CurrentThread.ManagedThreadId);
}
}
static void Main(string[] args)
{
Worker.LogThread("Enter Main");
var cts = new CancellationTokenSource(5000); // cancel after 5s
var worker = new Worker(cts.Token);
Task receiver = Task.Run(() => worker.ReceiverRun());
Task main = worker.ProcessAsync();
try
{
Task.WaitAll(main, receiver);
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e.Message);
}
Worker.LogThread("Leave Main");
Console.ReadLine();
}
}
}
This is not much different from doing Task.Run(() => task.SetResult(msg)) inside ReceiverRun. The only advantage I can think of is that you have an explicit control over when to switch threads. This way, you can stay on the same thread for as long as possible (e.g., for task2, task3, task4, but you still need another thread switch after task4 to avoid a deadlock on task5.Wait()).
Both solutions would eventually make the thread pool grow, which is bad in terms of performance and scalability.
Now, if we replace task.Wait() with await task everywhere inside ProcessAsync in the above code, we will not have to use await Task.Yield and there still will be no deadlocks. However, the whole chain of await calls after the 1st await task1 inside ProcessAsync will actually be executed on the ReceiverRun thread. As long as we don't block this thread with other Wait()-style calls and don't do a lot of CPU-bound work as we're processing messages, this approach might work OK (asynchronous IO-bound await-style calls still should be OK, and they may actually trigger an implicit thread switch).
That said, I think you'd need a separate thread with a serializing synchronization context installed on it for processing messages (similar to WindowsFormsSynchronizationContext). That's where your asynchronous code containing awaits should run. You'd still need to avoid using Task.Wait on that thread. And if an individual message processing takes a lot of CPU-bound work, you should use Task.Run for such work. For async IO-bound calls, you could stay on the same thread.
You may want to look at ActionDispatcher/ActionDispatcherSynchronizationContext from #StephenCleary's
Nito Asynchronous Library for your asynchronous message processing logic. Hopefully, Stephen jumps in and provides a better answer.
"My assumption was that the second SendAwaitResponse would execute in a ThreadPool thread but it continues in the thread created for ReceiverRun."
It depends entirely on what you do within SendAwaitResponse. Asynchrony and concurrency are not the same thing.
Check out: C# 5 Async/Await - is it *concurrent*?
A little late to the party, but here's my solution which i think is added value.
I've been struggling with this also, i've solved it by capturing the SynchronizationContext on the method that is awaited.
It would look something like:
// just a default sync context
private readonly SynchronizationContext _defaultContext = new SynchronizationContext();
void ReceiverRun()
{
while (true) // <-- i would replace this with a cancellation token
{
var msg = ReadNextMessage();
TaskWithContext<TResult> task = requests[msg.RequestID];
// if it wasn't a winforms/wpf thread, it would be null
// we choose our default context (threadpool)
var context = task.Context ?? _defaultContext;
// execute it on the context which was captured where it was added. So it won't get completed on this thread.
context.Post(state =>
{
if (msg.Error == null)
task.TaskCompletionSource.SetResult(msg);
else
task.TaskCompletionSource.SetException(new Exception(msg.Error));
});
}
}
public static Task<Response> SendAwaitResponse(string msg)
{
// The key is here! Save the current synchronization context.
var t = new TaskWithContext<Response>(SynchronizationContext.Current);
requests.Add(GetID(msg), t);
stream.Write(msg);
return t.TaskCompletionSource.Task;
}
// class to hold a task and context
public class TaskWithContext<TResult>
{
public SynchronizationContext Context { get; }
public TaskCompletionSource<TResult> TaskCompletionSource { get; } = new TaskCompletionSource<Response>();
public TaskWithContext(SynchronizationContext context)
{
Context = context;
}
}

Categories

Resources