How to create and use a custom Awaitable in c#? - c#

I'm trying to implement a custom awaiteable to execute await Thread.SleepAsync() without creating any additional threads.
Here's what I've got:
class AwaitableThread : INotifyCompletion
{
public AwaitableThread(long milliseconds)
{
var timer = new Timer(obj => { IsCompleted = true; }, null, milliseconds, Timeout.Infinite);
}
private bool isCompleted = false;
public bool IsCompleted
{
get { return isCompleted; }
set { isCompleted = value; }
}
public void GetResult()
{}
public AwaitableThread GetAwaiter() { return this; }
public void OnCompleted(Action continuation)
{
if (continuation != null)
{
continuation();
}
}
}
And here's how the sleep would work:
static async Task Sleep(int milliseconds)
{
await new AwaitableThread(milliseconds);
}
The problem is that this function returns immidiatly, even though in OnCompleted, IsCompleted is still false.
What am I doing wrong?

Fully implementing the awaitable pattern for production use is a tricky business - you need to capture the execution context, amongst other things. Stephen Toub's blog post on this has a lot more detail. In many cases, it's easier to piggy-back onto Task<T> or Task, potentially using TaskCompletionSource. For example, in your case, you could write the equivalent of Task.Delay like this:
public Task MyDelay(int milliseconds)
{
// There's only a generic TaskCompletionSource, but we don't really
// care about the result. Just use int as a reasonably cheap version.
var tcs = new TaskCompletionSource<int>();
Timer timer = new Timer(_ => tcs.SetResult(0), null, milliseconds,
Timeout.Infinite);
// Capture the timer variable so that the timer can't be garbage collected
// unless the task is (in which case it doesn't matter).
tcs.Task.ContinueWith(task => timer = null);
return tcs.Task;
}
You can now await that task, just like you can await the result of Task.Delay.

Related

async methods using or not using the threadpool, being scalable or not

can you please help me understand the difference between the two methods here:
1) why does the first use the thread pool and the second doesn't?
2) Why does the second give you scalability, but the first doesn't - is this related to thread pools?
3) How can I call the two methods in main to make their purpose more obvious (and better high light their differences)?
4) I know async Task methods can be called with await, what about Tasks that lack async like these methods?
public class _12_MyClass
{
public Task SleepAsyncA(int millisecondsTimeout)
{
return Task.Run(() => Thread.Sleep(millisecondsTimeout));
}
public Task SleepAsyncB(int millisecondsTimeout)
{
TaskCompletionSource<bool> tcs = null;
var t = new Timer(delegate { tcs.TrySetResult(true); }, null, -1, -1);
tcs = new TaskCompletionSource<bool>(t);
t.Change(millisecondsTimeout, -1);
return tcs.Task;
}
public static void Main()
{
}
}

Do Multi delegate Async Actions Only work with Begin Invoke

I'm trying to understand async actions and I'm a bit confused.
Actions are just glorified Delegates. Given the Actions
Action act = null;
act += () => { Console.WriteLine("Sync"); };
act += async () => { await File.AppendAllLinesAsync("C:/Test.Txt",
new[] { "Async File Operation" });
};
How can we invoke this async seeing as one of the delegates is async and the other is not. I've seen some extension methods in other SO answers simplified for the example would look like so:
public static void InvokeAsync(this Action action, AsyncCallback ar, object userObject = null)
{
var listeners = action.GetInvocationList();
foreach (var t in listeners)
{
var handler = (Action)t;
handler.BeginInvoke(ar, userObject);
}
}
I'm concerned if this even works because it looks like it invokes your callback for each listener which doesn't make sense.
I've only been using async with the more friendly version async/await so I do not understand this syntax as much. (I'm assuming the callback would be everything after the await and the userObject is equivalent to the dreadful SyncronizationContext that causes deadlocks if when calling sync without ConfigureAwait(false), but that is just a guess)
This is syntax inconvenient so I would perfer to use async await syntax, since async/await is called using duck-typing. I've read a blog about using async with delegates which for the example
public static class DelegateExtensions
{
public static TaskAwaiter GetAwaiter(this Action action)
{
Task task = new Task(action);
task.Start();
return task.GetAwaiter();
}
}
This too concerns me for a few reason, this looks much like an anti pattern.
Isn't this just creating a task which will run my action synchronous on a seperate thread? I also don't see this run through the invocation list.
Are either of these methods proper for invoking run delegates asynchronously?
Is there a way I can invoke an async delegate with the await syntax while still fully leveraging async?
What is the proper way to invoke async delegates with multiple functions in the invocation list?
I think Eric Lippert's comment have clarified the situation more than I could ever.
Overall, if you need to act on the return type of a method, you shouldn't use multicast delegates. If you still have to, at least use a Func<Task> signature, then you can iterate on each individual delegate using GetInvocationList, as explained here.
But would it be really impossible to work your way out of a multicast delegate with async void method?
It turns out that you can be notified of beginning and end of async void methods by using a custom synchronization context and overriding the OperationStarted and OperationCompleted methods. We can also override the Post method to set the synchronization context of child operations, to capture subsequent async void calls.
Piecing it together, you could come with something like:
class Program
{
static async Task Main(string[] args)
{
Action act = null;
act += () => { Console.WriteLine("Sync"); };
act += async () =>
{
Callback();
await Task.Delay(1000);
Console.WriteLine("Async");
};
await AwaitAction(act);
Console.WriteLine("Done");
Console.ReadLine();
}
static async void Callback()
{
await Task.Delay(2000);
Console.WriteLine("Async2");
}
static Task AwaitAction(Action action)
{
var delegates = action.GetInvocationList();
var oldSynchronizationContext = SynchronizationContext.Current;
var asyncVoidSynchronizationContext = new AsyncVoidSynchronizationContext();
try
{
SynchronizationContext.SetSynchronizationContext(asyncVoidSynchronizationContext);
var tasks = new Task[delegates.Length];
for (int i = 0; i < delegates.Length; i++)
{
((Action)delegates[i]).Invoke();
tasks[i] = asyncVoidSynchronizationContext.GetTaskForLastOperation();
}
return Task.WhenAll(tasks);
}
finally
{
SynchronizationContext.SetSynchronizationContext(oldSynchronizationContext);
}
}
}
public class AsyncVoidSynchronizationContext : SynchronizationContext
{
private TaskCompletionSource<object> _tcs;
private Task _latestTask;
private int _operationCount;
public Task GetTaskForLastOperation()
{
if (_latestTask != null)
{
var task = _latestTask;
_latestTask = null;
return task;
}
return Task.CompletedTask;
}
public override void Post(SendOrPostCallback d, object state)
{
Task.Run(() =>
{
SynchronizationContext.SetSynchronizationContext(this);
d(state);
});
}
public override void OperationStarted()
{
if (Interlocked.Increment(ref _operationCount) == 1)
{
// First operation
_tcs = new TaskCompletionSource<object>();
_latestTask = _tcs.Task;
}
base.OperationStarted();
}
public override void OperationCompleted()
{
if (Interlocked.Decrement(ref _operationCount) == 0)
{
// Last operation
_tcs.TrySetResult(null);
}
base.OperationCompleted();
}
}
The output would be:
Sync
Async
Async2
Done
Of course, this code is provided just for recreational purpose. There's plenty of limitations, such as the fact the fact that it wouldn't work as-is if you're already using a synchronization context (such as the WPF one). I'm also certain that it has a few subtle bugs and concurrency issues here and there.

Await on abstracted asynchronous task

I am very new to the async/await usage. I am trying to abstract the asynchrony and await conditionally in the UI. I have an abstract base class:
public abstract class Base
{
public abstract bool IsRunning { get; }
public abstract Task<bool> Run();
}
and from it some derived instances, first one being synchronous:
internal class Derived1 : Base
{
private readonly Base baseCase;
private Task<bool> task;
public Derived1(Base baseCase)
{
this.baseCase = baseCase;
}
public override bool IsRunning
{
get { return false; }
}
public override Task<bool> Run()
{
task = new Task<bool>(() =>
{
bool ok = DoSomething();
return ok;
});
return task;
}
}
and a derived class for an asynchronous implementation:
internal class Derived2 : Base
{
private readonly Base baseCase;
private Task<bool> task;
public Derived2(Base baseCase)
{
this.baseCase = baseCase;
}
public override bool IsRunning
{
get { return task != null && task.Status == TaskStatus.Running; }
}
public override Task<bool> Run()
{
task = new Task<bool>(() =>
{
bool ok = DoSomething();
return ok;
});
return task;
}
}
Then in the UI, I would like to await on asynchronous task (if user specified so in a run-time config), as follows:
internal class CaseMenuHandler
{
private async void OnRun(object sender, EventArgs args)
{
foreach (var case in Cases)
{
Base baseCaseRunner = GetCaseRunner(case);
try
{
bool ok = true;
if( something_holds ) {
ok = await baseCaseRunner.Run();
}
else {
ok = baseCaseRunner.Run().Result;
}
}
catch (Exception e)
{
LogError(...);
}
}
}
Hope this is clear. Can I do the above, specifically awaiting conditionally inside an if block? Ideally I would like to make the Base class only return bool and not Task<bool> for the Run method, and only have the Derived2 class override to return a Task<bool>, but I am not clear on how to do that. Perhaps I should return the task.Result inside the Run method of Derived2? If there's a better way to this including the abstraction or any other corrections, please let me know. Appreciate any ideas.
EDIT #1
The Run method form for the synchronous implementation in Derived1 has been clarified in the responses below. I am not allowed to change the signature of the DoSomething method though, so given that, my Run method in Derived2 (asynchronous implementation) looks as follows now (thanks to #Stripling's comments):
public override async Task<bool> Run()
{
task = new Task<bool>(() =>
{
bool ok = DoSomething();
return ok;
});
task.Start();
return await task;
}
EDIT #2:
When I try the above (also tried putting a task.Start() call after the task definition, I get the following error:
Cross-thread operation not valid: Application accessed domain object from a thread other than a legal thread.
Can I do the above, specifically awaiting conditionally inside an if block?
You can, but you shouldn't have to. If you do things right, there's no great advantage to specifically invoking a synchronous task in a blocking fashion: as a general rule, you can just await the Task that's returned, and if it represents a synchronous task then the await will be resolved synchronously with very little overhead.
When I say "if you do things right", here's the right way:
// synchronous
public override Task<bool> Run()
{
var result = DoSomething();
return Task.FromResult(result);
}
// asynchronous
public override async Task<bool> Run()
{
var result = await DoSomethingAsync();
return result;
}
awaiting the result of the first example above will not do any thread-switching or anything like that. awaiting the result of the second might, depending on the implementation of DoSomethingAsync(). There's no particular need for a layer of abstraction: you can always check a Task to whether it's completed or not, and awaiting an already-completed task will always return a value immediately.
I don't see how your synchronous version is synchronous, you still use the Task.Run(, I would have expected
internal class Derived1 : Base
{
private readonly Base baseCase;
private Task<bool> task;
public Derived1(Base baseCase)
{
this.baseCase = baseCase;
}
public override bool IsRunning
{
get { return false; }
}
public override Task<bool> Run()
{
bool ok = DoSomething();
return Task.FromResult(ok);
}
}
If you do it that way instead of the way you are doing it, your other code just becomes
private async void OnRun(object sender, EventArgs args)
{
foreach (var case in Cases)
{
Base baseCaseRunner = GetCaseRunner(case);
try
{
bool ok = true;
ok = await baseCaseRunner.Run();
}
catch (Exception e)
{
LogError(...);
}
}
}
The asynchronous version will run asynchronously and the synchronous version will run synchronously.
Your "async version" is not really async either, see Stripling's answer for the correct way to do that method.
Then in the UI, I would like to await on asynchronous task (if user specified so in a run-time config)
First off, I just have to say that this is a really bad idea. Some things should be configurable, and some should not. The asynchrony of operations should not be configurable. Period. This is a horrible design, and the first thing I would do is push back hard against ridiculous "requirements" like this. It literally makes the same amount of sense as a configurable flag for whether or not to throw exceptions.
That said, it can be done. It's painful, difficult to maintain, and completely useless at the end of the day. But hey, I assume you're getting paid for this so it's all good, eh?
If you must do this for political reasons (there are absolutely no valid technical reasons), then I recommend you use the Boolean Argument Hack from my article on brownfield async. One problem with just blocking (Result) is that it doesn't work if Run uses await (for reasons described on my blog).
The boolean argument hack simply adds a boolean argument indicating whether the method is expected to complete synchronously or not.
public abstract class Base
{
public abstract Task<bool> RunAsync(bool sync);
}
The semantics here are that if sync is true, then the task returned from RunAsync must already be completed.
Your implementation then looks like:
internal class Derived1 : Base
{
public override async Task<bool> RunAsync(bool sync)
{
IsRunning = true;
try
{
if (sync)
return DoSomething();
return await Task.Run(() => DoSomething());
}
finally
{
IsRunning = false;
}
}
}
And it's called like:
private async void OnRun(object sender, EventArgs args)
{
foreach (var case in Cases)
{
Base baseCaseRunner = GetCaseRunner(case);
try
{
bool sync = !something_holds;
bool ok = await baseCaseRunner.RunAsync(sync);
}
catch (Exception e)
{
LogError(...);
}
}
}
Note that it can always be called with await, but OnRun will actually be synchronous if sync is true. This is due to the "await fast path" - the fact that await first checks whether the task is already complete, and if it is, it continues synchronously (as described in my async intro blog post).
Use Task.FromResult to return a task that contains the result that was computed synchronously, and await.
bool ok = DoSomething();
return Task.FromResult(ok);
As a side note I'd not put synchronous code in a method that was generally intended to be asynchronous (or that is synchronous in other classes/places) and vice versa. I'd use different interfaces/base classes for a synchronous and an asynchronous implementation.
interface IRunnable
{
bool IsRunning;
bool Run();
}
interface IRunnableAsync
{
bool IsRunning;
Task<bool> RunAsync();
}

How to make TaskCompletionSource.Task complete using specific TaskScheduler

How to make the completion of TaskCompletionSource.Task happen on specific TaskScheduler, when I call TaskCompletionSource.SetResult?
Currently, I'm using the idea I borrowed from this post:
static public Task<TResult> ContinueOnTaskScheduler<TResult>(
this Task<TResult> #this, TaskScheduler scheduler)
{
return #this.ContinueWith(
antecedent => antecedent,
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
scheduler).Unwrap();
}
So whenever I would return TaskCompletionSource.Task to the caller, I now return TaskCompletionSource.Task.ContinueOnTaskScheduler(scheduler) instead.
Is it possible to somehow avoid this another level of indirection of ContinueWith?
It would be interesting to know your goals behind this. Anyway, if you like to avoid the overhead of ContinueWith (which I think is quite low), you'd probably have to come up with your own version of a pattern similar to TaskCompletionSource.
It's not that complex. E.g., something like Promise below can be used in the same way you use TaskCompletionSource, but would allow to provide a custom TaskScheduler for completion (disclaimer: almost untested):
public class Promise
{
readonly Task _task;
readonly CancellationTokenSource _cts;
readonly object _lock = new Object();
Action _completionAction = null;
// public API
public Promise()
{
_cts = new CancellationTokenSource();
_task = new Task(InvokeCompletionAction, _cts.Token);
}
public Task Task { get { return _task; } }
public void SetCompleted(TaskScheduler sheduler = null)
{
lock(_lock)
Complete(sheduler);
}
public void SetException(Exception ex, TaskScheduler sheduler = null)
{
lock (_lock)
{
_completionAction = () => { throw ex; };
Complete(sheduler);
}
}
public void SetException(System.Runtime.ExceptionServices.ExceptionDispatchInfo edi, TaskScheduler sheduler = null)
{
lock (_lock)
{
_completionAction = () => { edi.Throw(); };
Complete(sheduler);
}
}
public void SetCancelled(TaskScheduler sheduler = null)
{
lock (_lock)
{
// don't call _cts.Cancel() outside _completionAction
// otherwise the cancellation won't be done on the sheduler
_completionAction = () =>
{
_cts.Cancel();
_cts.Token.ThrowIfCancellationRequested();
};
Complete(sheduler);
}
}
// implementation
void InvokeCompletionAction()
{
if (_completionAction != null)
_completionAction();
}
void Complete(TaskScheduler sheduler)
{
if (Task.Status != TaskStatus.Created)
throw new InvalidOperationException("Invalid task state.");
_task.RunSynchronously(sheduler?? TaskScheduler.Current);
}
}
On a side note, this version has an override for SetException(ExceptionDispatchInfo edi), so you could propagate the active exception's state from inside catch:
catch(Exception ex)
{
var edi = ExceptionDispatchInfo.Capture(ex);
promise.SetException(edi);
}
It's easy to create a generic version of this, too.
There's a downside of this approach, though. A 3rd party can do promise.Task.Run or promise.Task.RunSynchronously, as the Task is exposed in the TaskStatus.Created state.
You could add a check for that into InvokeCompletionAction, or you could probably hide it using nested tasks / Task.Unwrap (although the latter would bring some overhead back).

TPL Queue Processing

I'm currently working on a a project and I have a need to queue some jobs for processing, here's the requirement:
Jobs must be processed one at a time
A queued item must be able to be waited on
So I want something akin to:
Task<result> QueueJob(params here)
{
/// Queue the job and somehow return a waitable task that will wait until the queued job has been executed and return the result.
}
I've tried having a background running task that just pulls items off a queue and processes the job, but the difficulty is getting from a background task to the method.
If need be I could go the route of just requesting a completion callback in the QueueJob method, but it'd be great if I could get a transparent Task back that allows you to wait on the job to be processed (even if there are jobs before it in the queue).
You might find TaskCompletionSource<T> useful, it can be used to create a Task that completes exactly when you want it to. If you combine it with BlockingCollection<T>, you will get your queue:
class JobProcessor<TInput, TOutput> : IDisposable
{
private readonly Func<TInput, TOutput> m_transform;
// or a custom type instead of Tuple
private readonly
BlockingCollection<Tuple<TInput, TaskCompletionSource<TOutput>>>
m_queue =
new BlockingCollection<Tuple<TInput, TaskCompletionSource<TOutput>>>();
public JobProcessor(Func<TInput, TOutput> transform)
{
m_transform = transform;
Task.Factory.StartNew(ProcessQueue, TaskCreationOptions.LongRunning);
}
private void ProcessQueue()
{
Tuple<TInput, TaskCompletionSource<TOutput>> tuple;
while (m_queue.TryTake(out tuple, Timeout.Infinite))
{
var input = tuple.Item1;
var tcs = tuple.Item2;
try
{
tcs.SetResult(m_transform(input));
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}
}
public Task<TOutput> QueueJob(TInput input)
{
var tcs = new TaskCompletionSource<TOutput>();
m_queue.Add(Tuple.Create(input, tcs));
return tcs.Task;
}
public void Dispose()
{
m_queue.CompleteAdding();
}
}
I would go for something like this:
class TaskProcessor<TResult>
{
// TODO: Error handling!
readonly BlockingCollection<Task<TResult>> blockingCollection = new BlockingCollection<Task<TResult>>(new ConcurrentQueue<Task<TResult>>());
public Task<TResult> AddTask(Func<TResult> work)
{
var task = new Task<TResult>(work);
blockingCollection.Add(task);
return task; // give the task back to the caller so they can wait on it
}
public void CompleteAddingTasks()
{
blockingCollection.CompleteAdding();
}
public TaskProcessor()
{
ProcessQueue();
}
void ProcessQueue()
{
Task<TResult> task;
while (blockingCollection.TryTake(out task))
{
task.Start();
task.Wait(); // ensure this task finishes before we start a new one...
}
}
}
Depending on the type of app that is using it, you could switch out the BlockingCollection/ConcurrentQueue for something simpler (eg just a plain queue). You can also adjust the signature of the "AddTask" method depending on what sort of methods/parameters you will be queueing up...
Func<T> takes no parameters and returns a value of type T. The jobs are run one by one and you can wait on the returned task to get the result.
public class TaskQueue
{
private Queue<Task> InnerTaskQueue;
private bool IsJobRunning;
public void Start()
{
Task.Factory.StartNew(() =>
{
while (true)
{
if (InnerTaskQueue.Count > 0 && !IsJobRunning)
{
var task = InnerTaskQueue.Dequeue()
task.Start();
IsJobRunning = true;
task.ContinueWith(t => IsJobRunning = false);
}
else
{
Thread.Sleep(1000);
}
}
}
}
public Task<T> QueueJob(Func<T> job)
{
var task = new Task<T>(() => job());
InnerTaskQueue.Enqueue(task);
return task;
}
}

Categories