I'm wrapping a library for my own use. To get a certain property I need to wait for an event. I'm trying to wrap that into an async call.
Basically, I want to turn
void Prepare()
{
foo = new Foo();
foo.Initialized += OnFooInit;
foo.Start();
}
string Bar
{
return foo.Bar; // Only available after OnFooInit has been called.
}
Into this
async string GetBarAsync()
{
foo = new Foo();
foo.Initialized += OnFooInit;
foo.Start();
// Wait for OnFooInit to be called and run, but don't know how
return foo.Bar;
}
How could this best be accomplished? I could just loop and wait, but I'm trying to find a better way such as using Monitor.Pulse(), AutoResetEvent or something else.
Thats where TaskCompletionSource comes into play. There is little room for the new async keyword here. Example:
Task<string> GetBarAsync()
{
TaskCompletionSource<string> resultCompletionSource = new TaskCompletionSource<string>();
foo = new Foo();
foo.Initialized += OnFooInit;
foo.Initialized += delegate
{
resultCompletionSource.SetResult(foo.Bar);
};
foo.Start();
return resultCompletionSource.Task;
}
Sample use (with fancy async)
async void PrintBar()
{
// we can use await here since bar returns a Task of string
string bar = await GetBarAsync();
Console.WriteLine(bar);
}
Related
I have a legacy scenario where a ref bool was being used to send a cancellation signal to an implementation. Now, I want to call a Task-based library method that takes a CancellationToken instance, which I also want to be cancelled when the boolean changes value.
This is what I have to work with:
void Method(ref bool isCancelled)
{
while (!isCancelled)
{
...
DoThis();
DoThat();
...
}
}
And this is what I want to do:
Task MethodAsync(ref bool isCancelled)
{
while (!isCancelled)
{
...
DoThis();
await DoTheNewThingAsync(isCancelled.ToCancellationToken());
DoThat();
...
}
}
ToCancellationToken() doesn't exist in this context of course, and is used just to show the intent.
I tried to create a custom implementation of CancellationTokenSource but there is nothing virtual in the class that I could work with. It's also not possible to create a custom CancellationToken directly since it is a struct and cannot be inherited.
I'm aware that using a ref bool is a poor practice but I can't currently change the underlying implementation that relies on it, so I need a way to use it's value as the cancellation mechanism for the task-based call.
It's complicated. For a few reasons:
You cannot pass a parameter by ref to an async method. You're using await, but to use await, your method needs to be marked async. And async methods cannot have ref parameters. For example, this will not compile:
async Task MethodAsync(ref bool isCancelled)
{
while (!isCancelled)
{
DoThis();
await DoTheNewThingAsync(isCancelled.ToCancellationToken());
DoThat();
}
}
That will give you the compiler error:
CS1988: Async methods cannot have ref, in or out parameters
You cannot use ref parameters in anonymous methods. I thought about using a Timer to check the variable. Something like this:
public static CancellationToken ToCancellationToken(ref bool isCancelled)
{
var tokenSource = new CancellationTokenSource();
var timer = new System.Timers.Timer()
{
AutoReset = true,
Interval = 100
};
timer.Elapsed += (source, e) =>
{
if (isCancelled)
{
tokenSource.Cancel();
timer.Dispose();
}
};
timer.Enabled = true;
return tokenSource.Token;
}
But that gives you the compiler error:
CS1628: Cannot use ref, out, or in parameter 'isCancelled' inside an anonymous method, lambda expression, query expression, or local function
I don't see any other way to get the bool into the event handler by reference.
The closest I could get is something like this:
void Method(ref bool isCancelled)
{
while (!isCancelled)
{
DoThis();
using (var tokenSource = new CancellationTokenSource()) {
var mytask = DoTheNewThingAsync(tokenSource.Token);
while (true)
{
//wait for either the task to finish, or 100ms
if (Task.WaitAny(mytask, Task.Delay(100)) == 0)
{
break; //mytask finished
}
if (isCancelled) tokenSource.Cancel();
}
// This will throw an exception if an exception happened in
// DoTheNewThingAsync. Otherwise we'd never know if it
// completed successfully or not.
mytask.GetAwaiter().GetResult();
}
DoThat();
}
}
However, that blocks the caller, so I don't entirely see how that could even be useful (how can the caller change isCancelled if it's blocked?). But that's kind of what your existing method is doing, so maybe it would work?
But this is super hacky. If you can at all control how anything is done upstream, do that instead.
I've hacked up a somewhat working solution:
public static class TaskRefBoolCancellable
{
public static T SynchronousAwait<T>(Func<CancellationToken, Task<T>> taskToRun, ref bool isCancelled)
{
using (var cts = new CancellationTokenSource())
{
var runningTask = taskToRun(cts.Token);
while (!runningTask.IsCompleted)
{
if (isCancelled)
cts.Cancel();
Thread.Sleep(100);
}
return runningTask.Result;
}
}
}
void Method(ref bool isCancelled)
{
while (!isCancelled)
{
...
DoThis();
var result = TaskRefBoolCancellable.SynchronousAwait(DoTheNewThingAsync, ref isCancelled);
DoThat();
...
}
}
WARNING: This code runs synchronously on calling thread. So there are no guarantees it will work nicely with other parts of the code, as it blocks the calling thread. Also, it polls the isCancelled variable, making it both ineffective and the cancellation is not immediate.
I would consider this a stop-gap solution as you replace the ref bool isCancelled with proper task-based cancellation.
This is an attempted improvement on Euphoric's inventive solution. Instead of Thread.Sleep, this one uses the Task.Wait overload that accepts a timeout. This way no extra delay will be imposed to the completion of the task.
public static void Wait(Func<CancellationToken, Task> taskFactory,
ref bool cancel, int pollInterval = 100)
{
using (var cts = new CancellationTokenSource())
{
if (cancel) cts.Cancel();
var task = taskFactory(cts.Token);
while (!cancel)
{
if (task.Wait(pollInterval)) return;
}
cts.Cancel();
task.Wait();
}
}
Usage example:
Wait(DoTheNewThingAsync, ref isCancelled);
If you are making a method async Task and still want to use bool semantics, you have to pass an object so that in can keep the reference to the bool value. This can be done without any blocking operations if bool parameter can be converted to Ref<bool> in client code:
public class Ref
{
public static Ref<T> Create<T>(T value) => new Ref<T>(value);
}
public class Ref<T> : Ref
{
private T value;
public Ref(T value) => Value = value;
public T Value
{
get => value;
set
{
this.value = value;
OnChanged?.Invoke(value);
}
}
public override string ToString() => Value?.ToString() ?? "";
public static implicit operator T(Ref<T> r) => r.Value;
public event Action<T> OnChanged;
}
public static class RefExtensions
{
public static CancellationToken ToCancellationToken(this Ref<bool> cancelled)
{
var cts = new CancellationTokenSource();
cancelled.OnChanged += value => { if (value) cts.Cancel(); };
return cts.Token;
}
}
public async Task Method(Ref<bool> isCancelled)
{
var cancellationToken = isCancelled.ToCancellationToken();
while(!isCancelled)
{
...
DoThis();
await DoTheNewThingAsync(cancellationToken);
DoThat();
...
}
}
public class Tests
{
[Fact]
public async Task Fact()
{
var cancelled = Ref.Create(false);
Task.Run(async () =>
{
await Task.Delay(500);
cancelled.Value = true;
});
var task = Method(cancelled);
await Task.Delay(1000);
task.Status.Should().Be(TaskStatus.RanToCompletion);
}
}
Suppose I have a List<Task>:
private readonly List<Task> _tasks = new List<Task>(new Task[9]);
I want create a Task for start the DoWorkAsync method available inside the class Foo, so what I did is the following:
_tasks[0] = new Task<Foo>(() => new Foo().DoWorkAsync());
so the Foo class contains DoWorkAsync method which have a design similar to this:
public async Task HeavyAsync()
{
while (true)
{
string newData = DateTime.Now.ToLongTimeString();
Console.WriteLine(newData);
await Task.Delay(200);
}
}
actually I can start the Task using _tasks[0].Start();.
This works, but the main problem is that I want access to the public property of Foo class and I can't, because when I type this: _tasks[0].
I'll get the following method:
I also tried using GetAwaiter() and await:
var foo = await _tasks[0];
but I'll get the following error:
Cannot assign void to an implicitly-typed local variable
How can I access to the Foo properties?
You have to change the interface of your method. A task is just a "function pointer" that is executed and then finished. If you need the object, that contains the executed function, then you have to save or return it somewhere.
I would do the following: change the async method to return an object like:
public async Task<Foo> HeavyAsync()
{
while (true)
{
string newData = DateTime.Now.ToLongTimeString();
Console.WriteLine(newData);
await Task.Delay(200);
}
return this;
}
then this statement
var foo = await _tasks[0];
should give you with foo a reference to your Foo-object.
UPDATE:
Or you give your class Foo the following property and methods:
class Foo
{
private Task runningTask {get;set;}
public void StartTask()
{
runningTask = Task.Start( () => ....);
}
public async Task WaitTask()
{
await runningTask;
}
public bool IsRunning => runningTask != null && runningTask.Status......
And instead of holding a list of Task in your calling method, you might hold the list of Foo instances.
Please consider code below. Each time I run the code, output will be always 0 and 3. I am sure it has something to do with single instance but didn't have any explanation why this is happening. It will be great if you can help me understand this. Thank you for your help.
Is this happening because variable points to a different location in heap each time we initialize it ?
public class Helper
{
List<int> list = new List<int>();
public List<int> GetList
{
get
{
return list;
}
}
public async Task<bool> Process()
{
await Task.Delay(1);
//sleep this thread for 6 seconds
Thread.Sleep(6000);
//When I debug, both of the thread adds into the list
//but first thread always have zero element on this list, if it adds to the list then where it is getting lost ?
//not sure why ? Has to do something with the variable below _confighelper
//but why it behaves likes this ? what would be the best explanation?
//where this variable is getting lost ?
list.Add(1);
list.Add(2);
list.Add(3);
return true;
}
}
public class RunOp
{
//Has to do something with single instance
Helper _configHelper;
public async Task Run()
{
_configHelper = new Helper();
var val = await _configHelper.Process();
Console.WriteLine(_configHelper.GetList.Count);
}
}
class Program
{
static void Main(string[] args)
{
RunOp op = new RunOp();
Task.Factory.StartNew(async () =>
{
await op.Run();
});
Thread.Sleep(4000);
//Start another thread after 4 seconds
Task.Factory.StartNew(async () =>
{
await op.Run();
});
Console.ReadLine();
}
}
This is a simple case of thread safety, and this is not thread safe
The problem is RunOp has an internal Helper, which gets overwritten and showing (what seems) inconsistent results because of the thread sleeps and delays.
Here is a thread safe version
public class RunOp
{
private SemaphoreSlim slim = new SemaphoreSlim(1,1);
//Has to do something with single instance
Helper _configHelper;
public async Task Run()
{
await slim.WaitAsync();
_configHelper = new Helper();
var val = await _configHelper.Process();
Console.WriteLine(_configHelper.GetList.Count);
slim.Release();
}
// or
public async Task Run()
{
Helper configHelper = new Helper();
var val = await configHelper.Process();
Console.WriteLine(configHelper.GetList.Count);
}
}
I know this is only an academic problem, but this really should be refactored and thought through again
I know how to make Async methods but say I have a method that does a lot of work then returns a boolean value?
How do I return the boolean value on the callback?
Clarification:
public bool Foo(){
Thread.Sleep(100000); // Do work
return true;
}
I want to be able to make this asynchronous.
From C# 5.0, you can specify the method as
public async Task<bool> doAsyncOperation()
{
// do work
return true;
}
bool result = await doAsyncOperation();
There are a few ways of doing that... the simplest is to have the async method also do the follow-on operation. Another popular approach is to pass in a callback, i.e.
void RunFooAsync(..., Action<bool> callback) {
// do some stuff
bool result = ...
if(callback != null) callback(result);
}
Another approach would be to raise an event (with the result in the event-args data) when the async operation is complete.
Also, if you are using the TPL, you can use ContinueWith:
Task<bool> outerTask = ...;
outerTask.ContinueWith(task =>
{
bool result = task.Result;
// do something with that
});
Use a BackgroundWorker. It will allow you to get callbacks on completion and allow you to track progress. You can set the Result value on the event arguments to the resulting value.
public void UseBackgroundWorker()
{
var worker = new BackgroundWorker();
worker.DoWork += DoWork;
worker.RunWorkerCompleted += WorkDone;
worker.RunWorkerAsync("input");
}
public void DoWork(object sender, DoWorkEventArgs e)
{
e.Result = e.Argument.Equals("input");
Thread.Sleep(1000);
}
public void WorkDone(object sender, RunWorkerCompletedEventArgs e)
{
var result = (bool) e.Result;
}
Probably the simplest way to do it is to create a delegate and then BeginInvoke, followed by a wait at some time in the future, and an EndInvoke.
public bool Foo(){
Thread.Sleep(100000); // Do work
return true;
}
public SomeMethod()
{
var fooCaller = new Func<bool>(Foo);
// Call the method asynchronously
var asyncResult = fooCaller.BeginInvoke(null, null);
// Potentially do other work while the asynchronous method is executing.
// Finally, wait for result
asyncResult.AsyncWaitHandle.WaitOne();
bool fooResult = fooCaller.EndInvoke(asyncResult);
Console.WriteLine("Foo returned {0}", fooResult);
}
Perhaps you can try to BeginInvoke a delegate pointing to your method like so:
delegate string SynchOperation(string value);
class Program
{
static void Main(string[] args)
{
BeginTheSynchronousOperation(CallbackOperation, "my value");
Console.ReadLine();
}
static void BeginTheSynchronousOperation(AsyncCallback callback, string value)
{
SynchOperation op = new SynchOperation(SynchronousOperation);
op.BeginInvoke(value, callback, op);
}
static string SynchronousOperation(string value)
{
Thread.Sleep(10000);
return value;
}
static void CallbackOperation(IAsyncResult result)
{
// get your delegate
var ar = result.AsyncState as SynchOperation;
// end invoke and get value
var returned = ar.EndInvoke(result);
Console.WriteLine(returned);
}
}
Then use the value in the method you sent as AsyncCallback to continue..
You should use the EndXXX of your async method to return the value. EndXXX should wait until there is a result using the IAsyncResult's WaitHandle and than return with the value.
In the following code sample I have an Async Calculator class. This is injected with an ICalc, which will be a syncronous calculator. I use dependency injecting and mock the ICalc because this resembles my true scenario, though I guess the mocking isn't really of relevance to the question. The AsyncCalc has a function which will call another function asynchronously - taking a callback as parameter. And when the async function call finishes the callback will be triggered with the result.
Now I want to test my asynchronous function - checking that the callback is triggered with the expected parameter. This code seems to work. However, I feel like it might blow up at any time - and my concern is race condition of the callback to finish before the function ends and the test is terminated - as this will be run in a separate thread.
My question now is if I'm on the right track unit testing the async function, or if anyone can help me get on the right track..? What would feel better is if I could ensure that the callback is triggered right away - and preferably on the same thread I guess? Can/Should it be done?
public interface ICalc
{
int AddNumbers(int a, int b);
}
public class AsyncCalc
{
private readonly ICalc _calc;
public delegate void ResultProcessor(int result);
public delegate int AddNumbersAsyncCaller(int a, int b);
public AsyncCalc(ICalc calc)
{
_calc = calc;
}
public void AddNumbers(int a, int b, ResultProcessor resultProcessor)
{
var caller = new AddNumbersAsyncCaller(_calc.AddNumbers);
caller.BeginInvoke(a, b, new AsyncCallback(AddNumbersCallbackMethod), resultProcessor);
}
public void AddNumbersCallbackMethod(IAsyncResult ar)
{
var result = (AsyncResult)ar;
var caller = (AddNumbersAsyncCaller)result.AsyncDelegate;
var resultFromAdd = caller.EndInvoke(ar);
var resultProcessor = ar.AsyncState as ResultProcessor;
if (resultProcessor == null) return;
resultProcessor(resultFromAdd);
}
}
[Test]
public void TestingAsyncCalc()
{
var mocks = new MockRepository();
var fakeCalc = mocks.DynamicMock<ICalc>();
using (mocks.Record())
{
fakeCalc.AddNumbers(1, 2);
LastCall.Return(3);
}
var asyncCalc = new AsyncCalc(fakeCalc);
asyncCalc.AddNumbers(1, 2, TestResultProcessor);
}
public void TestResultProcessor(int result)
{
Assert.AreEqual(3, result);
}
You could use a ManualResetEvent to synchronize your threads.
In the following example, the test thread will block on the call to completion.WaitOne().
The callback for the async calculation stores the result and then signals the event by calling completion.Set().
[Test]
public void TestingAsyncCalc()
{
var mocks = new MockRepository();
var fakeCalc = mocks.DynamicMock<ICalc>();
using (mocks.Record())
{
fakeCalc.AddNumbers(1, 2);
LastCall.Return(3);
}
var asyncCalc = new AsyncCalc(fakeCalc);
var completion = new ManualResetEvent(false);
int result = 0;
asyncCalc.AddNumbers(1, 2, r => { result = r; completion.Set(); });
completion.WaitOne();
Assert.AreEqual(3, calcResult);
}
// ** USING AN ANONYMOUS METHOD INSTEAD
// public void TestResultProcessor(int result)
// {
// Assert.AreEqual(3, result);
// }
You could also use a "test runner" class to run the asserts in a loop. The loop would run the asserts in a try/catch. The exception handler would simply try to run the asserts again until a timeout has expired. I recently wrote a blog post about this technique. The example is in groovy, but is applicable to any language. Instead of passing a Closure, you would pass a Action in c#.
http://www.greenmoonsoftware.com/2013/08/asynchronous-functional-testing/