asnychronous callback - c#

I am new to asynchronous programming. I have a C# dll with an asynchronous method that gets called, takes a function pointer (delegate) and calls this callback function after "result" is calculated.
public delegate void CreatedDelegate(Foo result);
public void CreateAsync(CreatedDelegate createdCallback)
{
Task t = Task.Factory.StartNew(() =>
{
Foo result = ...
createdCallback(result);
});
}
The delegate callback of type "CreatedDelegate" is (in my case) a function pointer to a C++/CLI method that works with the result.
void CreatedCallback(Foo^ result)
{
// do something with result
}
So this asynchronous concept seems to work quite well in most cases, but sometimes I encounter some errors. How can I achieve it if the function "CreateAsync" is called multiple times with different computation effort, that the resulting calls to "CreatedCallback" just happen in the same order as originally "CreateAsync" was called? To make it clearer: The first call to "CreateAsync" should result in the first call to "CreatedCallback" even if a succeeding call of "CreateAsync" is faster and would actually call the callback earlier.
Maybe this can be done by allowing only one active new thread in the asynchronous "CreateAsync" at a time?

To process the callbacks in order, you'll need to implement some queueing of work items. The easiest way is probably to use BlockingCollection type (see MSDN documentation).
Instead of calling the callback, your CreateAsync method would add the task (together with the callback) to the queue:
// Queue to keep tasks and their callbacks
private BlockingCollection<Tuple<Task<Foo>, CreatedDelegate>>
queue = new BlockingCollection<Tuple<Task<Foo>, CreatedDelegate>>()
public void CreateAsync(CreatedDelegate createdCallback) {
Task<Foo> t = Task.Factory.StartNew(() => {
Foo result = ...
return result; });
queue.Add(Tuple.Create(t, createdCallback));
// ..
}
This will only add tasks and callbacks to the queue - to actually call the callback, you'll need another task that waits for the tasks in the queue (in the order in which they were added) and calls the callback:
Task.Factory.StartNew(() => {
while(true) { // while you keep calling 'CreateAsync'
// Get next task (in order) and its callback
Tuple<Task<Foo>, CreatedDelegate> op = queue.Take();
// Wait for the result and give it to callback
op.Item2(op.Item1.Result);
}
}

If order is important, then using Threads might be better:
thread queue = empty
for each task
{
if there are no free 'cpu'
wait on first thread in queue
remove thread from queue
call delegate
create thread
add thread to queue
}
while queue has threads
wait on first thread in queue
remove thread from queue
call delegate

Related

How to wait on Async tasks

static void Main(string[] args)
{
Action myAction = async () =>
{
await Task.Delay(5);
Console.WriteLine(Interlocked.Add(ref ExecutionCounter, 1));
};
var actions = new[] { myAction, myAction, myAction };
Task.WaitAll(actions.Select(a => Execute(a)).ToArray()); //This blocks, right?
Console.WriteLine("Done waiting on tasks.");
Console.ReadLine();
}
static int ExecutionCounter = 0;
private static Task Execute(Action a)
{
return Task.Factory.StartNew(async () =>
{
await Task.Delay(5);
a();
});
}
This seems simple enough, but naturally the output always looks like this (the order of the numbers change, of course):
Done waiting on tasks.
2
1
3
What am I missing here? Why doesn't Task.WaitAll block like I'm expecting it to?
So there are several separate bugs here.
First, for Execute, you're using StartNew with an async lambda. Since StartNew doesn't have a Task<Task> returning overload, like Task.Run does, you've got a method that returns a Task indicating when the asynchronous operation has finished starting, not when the asynchronous operation has finished, which means that the Task returned by Execute will be completed basically right away, rather than after Delay finishes or the action you call finishes. Additionally, there's simply no reason to use StartNew or Run at all when running asynchronous methods, you can just execute them normally and await them without pushing them to a thread pool thread.
Next, Execute accepts an Action, which implies that it's a synchronous method that doesn't compute any value. What you're providing is an asynchronous method, but as the delegate doesn't return a Task, Execute can't await it. If you want Execute to handle asynchronous methods, it needs to accept a delegate that returns a Task.
So given all of that Execute should look like this.
private static async Task Execute(Func<Task> action)
{
await Task.Delay(TimeSpan.FromMilliseconds(5));
await action();
}
Next onto the Main method. As mentioned before Execute is accepting an Action when you're trying to provide an async method. This means that when the action is run the code will continued executing before your actions have finished. You need to adjust it to using a Task returning method.
After all of that, your code still has a race condition in it, at a conceptual level, that will prevent you from theoretically getting the results in the right order. You're performing 3 different operations in parallel, and as a result of that, they can finish in any order. While you are atomically incrementing the counter, it's possible for one thread to increment the counter, then another to run, increment the counter, print its value, then have the other thread run again and print out the value, given you a possible output of what you have, even after fixing all of the bugs mentioned above. To ensure that the values are printed in order, you need to ensure that the increment and the console write are performed atomically.
Now you can write out your Main method like so:
int ExecutionCounter = 0;
object key = new object();
Func<Task> myAction = async () =>
{
await Task.Delay(TimeSpan.FromMilliseconds(5));
lock (key)
{
Console.WriteLine(++ExecutionCounter);
}
};
var actions = new[] { myAction, myAction, myAction };
Task.WaitAll(actions.Select(a => Execute(a)).ToArray()); //This blocks, right?
And yes, as your comment mentions, calling WaitAll will block, rather than being asynchronous.

What is the correct way to run synchronous method in asynchronously

I have an abstract class whose method is define as like this
public abstract class FooBase : IDisposable
{
protected abstract bool GetData(params object[] getDataParams);
}
I am using this abstract class like this and trying to run the GetData method asynchronously
public class SomeClass : FooBase
{
protected override bool GetData(params object[] getDataParams)
{
var task = Task.Factory.StartNew(() =>
{
using (var adapter = new DataAdapter())
{
// Take your time and fetch the data
}
});
task.Wait();
return true;
}
}
What I am trying to find out is: Am I doing it right or wrong, or if there is any other better way to achieve the same goal.
Update
If i change my method like this would it be called asynchronously or not
public class SomeClass : FooBase
{
protected override bool GetData(params object[] getDataParams)
{
var task = Task.Factory.StartNew(async () =>
{
using (var adapter = new DataAdapter())
{
// Take your time and fetch the data
}
});
task.Wait();
return true;
}
}
Appreciate your comments on this.
There is no way to run a synchronous method other than synchronously.
You can wrap the result in something that looks like it was run asynchronously (eg. Task.FromResult), or run in another thread.1 But the synchronous method will still block the thread it is running on.
(The reverse, blocking on an asynchronous operation, is trivial. This is why you need to have the underlying operations asynchronous because you can build both synchronous and asynchronous methods on top.)
Update (for update in question):
That additional code – specifically the task.Wait() statement – will cause the caller's thread to block while waiting for the task to complete. That task will run on another thread causing that thread to block. Ie. you are causing two threads (caller, and a thread pool thread) to block. If the underlying method was called directly only the caller's thread would be blocked.
You have two approaches:
Best: use ADO.NET's asynchronous operations. (This means not using DataTables/DataAdaptor but IMHO that's a good move anyway: all they do is move operations that should be done on the database into the client.)
Offload to another thread, but return a Task<TResult> to the caller, only marking the Task as complete then the underlying operation is complete. Something like:
protected override Task<bool> GetData(params object[] getDataParams) {
var tcs = new TaskCompletionSource<bool>();
Task.Factory.StartNew(async () => {
using (var adapter = new DataAdapter()) {
// Take your time and fetch the data
tcs.SetResult(the-result);
}
});
return tcs.Task;
}
Note here the return from GetData is a Task<bool>: the caller needs to either wait or do something else concurrently and then get the result of the data operation. If the caller just waits then you have two blocked threads. (C# 5's await is different: the caller also becomes asynchronous.)
1 For the avoidance of doubt: this can be made to look like a normal, Task<T> returning, asynchronous method (eg. making use of TaskCompletionSource<T> off loading the blocking from the current thread to some thread in the thread pool). But it is still a blocking operation: just blocking a different thread.

Usage criteria for IAsyncResult.IsCompleted, iftAR.AsyncWaitHandle.WaitOne and AsyncCallback

I am learning the async concept of delegates and here I am confused on the difference between using the IAsyncResult.IsCompleted, iftAR.AsyncWaitHandle.WaitOne and AsyncCallback (in which you define new function with IAsyncResult as parameter).
I'm confused because suppose you use while loop to check for above 3 values, then in each of the 3 cases, you are checking in while loop whether the particular operation has completed executing. Then, what is the difference between the 3?
CASE 1 Code:
static void Main(string[] args)
{
Console.WriteLine("***** Async Delegate Invocation *****");
// Print out the ID of the executing thread.
Console.WriteLine("Main() invoked on thread {0}.",Thread.CurrentThread.ManagedThreadId);
// Invoke Add() on a secondary thread.
BinaryOp b = new BinaryOp(Add);
IAsyncResult iftAR = b.BeginInvoke(10, 10, null, null);
// This message will keep printing until
// the Add() method is finished.
while(!iftAR.IsCompleted)
{
Console.WriteLine("Doing more work in Main()!");
Thread.Sleep(1000);
}
// Now we know the Add() method is complete.
int answer = b.EndInvoke(iftAR);
Console.WriteLine("10 + 10 is {0}.", answer);
Console.ReadLine();
}
static int Add(int x, int y)
{
// Print out the ID of the executing thread.
Console.WriteLine("Add() invoked on thread {0}.", Thread.CurrentThread.ManagedThreadId);
// Pause to simulate a lengthy operation.
Thread.Sleep(5000);
return x + y;
}
CASE 2 code:If we replace the while loop with foll code:
while (!iftAR.AsyncWaitHandle.WaitOne(1000, true))
{
Console.WriteLine("Doing more work in Main()!");
}
CASE 3 code:If we replace the while loop from CASE 1 with foll code and add the AddComplete method:
while (!isDone)
{
Thread.Sleep(1000);
Console.WriteLine("Working....");
}
static void AddComplete(IAsyncResult itfAR)
{
Console.WriteLine("AddComplete() invoked on thread {0}.", Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("Your addition is complete");
isDone = true;
}
The IAsyncResult is part of the APM pattern, which in itself has not much to do with delegates, but just uses a delegate for the callback. This pattern needs to be looked at as its own (quite complex) topic.
MSDN
That being said, the difference in summary is the following:
IsComplete is just a flag which lets you poll/check if the operation is complete or if it is still running.
The WaitHandle wraps an operating system primitive and allows to join a thread without using any CPU for the duration of the async operation, optionally with a timeout. When the timeout on WaitOne is set to 0, the operation is basically doing the same as IsComplete but at a much higher overhead cost.
The callback however allows to fire off an operation and "forget" about it; the callback will be called when the operation is complete, therefore allowing to continue at that point without actively polling or waiting. In the callback, the IsComplete will always be true and invoking WaitOne.Join would always immediately return.
Note: in your AddComplete callback, you should invoke the EndInvoke, not just set a synchronisation flag.
So if your use case is a while loop (a "spinning wait"), you should poll the IsComplete flag. The other two are used in other situations.

IAsyncResult.AsyncWaitHandle.WaitOne() completes ahead of callback

Here is the code:
class LongOp
{
//The delegate
Action longOpDelegate = LongOp.DoLongOp;
//The result
string longOpResult = null;
//The Main Method
public string CallLongOp()
{
//Call the asynchronous operation
IAsyncResult result = longOpDelegate.BeginInvoke(Callback, null);
//Wait for it to complete
result.AsyncWaitHandle.WaitOne();
//return result saved in Callback
return longOpResult;
}
//The long operation
static void DoLongOp()
{
Thread.Sleep(5000);
}
//The Callback
void Callback(IAsyncResult result)
{
longOpResult = "Completed";
this.longOpDelegate.EndInvoke(result);
}
}
Here is the test case:
[TestMethod]
public void TestBeginInvoke()
{
var longOp = new LongOp();
var result = longOp.CallLongOp();
//This can fail
Assert.IsNotNull(result);
}
If this is run the test case can fail. Why exactly?
There is very little documentation on how delegate.BeginInvoke works. Does anyone have any insights they would like to share?
Update
This is a subtle race-condition that is not well documented in MSDN or elsewhere. The problem, as explained in the accepted answer, is that when the operation completes the Wait Handle is signalled, and then the Callback is executed. The signal releases the waiting main thread and now the Callback execution enters the "race". Jeffry Richter's suggested implementation shows what's happening behind the scenes:
// If the event exists, set it
if (m_AsyncWaitHandle != null) m_AsyncWaitHandle.Set();
// If a callback method was set, call it
if (m_AsyncCallback != null) m_AsyncCallback(this);
For a solution refer to Ben Voigt's answer. That implementation does not incur the additional overhead of a second wait handle.
The ASyncWaitHandle.WaitOne() is signaled when the asynchronous operation completes. At the same time CallBack() is called.
This means that the the code after WaitOne() is run in the main thread and the CallBack is run in another thread (probably the same that runs DoLongOp()). This results in a race condition where the value of longOpResult essentially is unknown at the time it is returned.
One could have expected that ASyncWaitHandle.WaitOne() would have been signaled when the CallBack was finished, but that is just not how it works ;-)
You'll need another ManualResetEvent to have the main thread wait for the CallBack to set longOpResult.
As others have said, result.WaitOne just means that the target of BeginInvoke has finished, and not the callback. So just put the post-processing code into the BeginInvoke delegate.
//Call the asynchronous operation
Action callAndProcess = delegate { longOpDelegate(); Callafter(); };
IAsyncResult result = callAndProcess.BeginInvoke(r => callAndProcess.EndInvoke(r), null);
//Wait for it to complete
result.AsyncWaitHandle.WaitOne();
//return result saved in Callafter
return longOpResult;
What is happening
Since your operation DoLongOp has completed, control resumes within CallLongOp and the function completes before the Callback operation has completed. Assert.IsNotNull(result); then executes before longOpResult = "Completed";.
Why? AsyncWaitHandle.WaitOne() will only wait for your async operation to complete, not your Callback
The callback parameter of BeginInvoke is actually an AsyncCallback delegate, which means your callback is called asynchronously. This is by design, as the purpose is to process the operation results asynchronously (and is the whole purpose of this callback parameter).
Since the BeginInvoke function actually calls your Callback function the IAsyncResult.WaitOne call is just for the operation and does not influence the callback.
See the Microsoft documentation (section Executing a Callback Method When an Asynchronous Call Completes). There is also a good explanation and example.
If the thread that initiates the asynchronous call does not need to be the thread that processes the results, you can execute a callback method when the call completes. The callback method is executed on a ThreadPool thread.
Solution
If you want to wait for both the operation and the callback, you need to handle the signalling yourself. A ManualReset is one way of doing it which certainly gives you the most control (and it's how Microsoft has done it in their docs).
Here is amended code using ManualResetEvent.
public class LongOp
{
//The delegate
Action longOpDelegate = LongOp.DoLongOp;
//The result
public string longOpResult = null;
// Declare a manual reset at module level so it can be
// handled from both your callback and your called method
ManualResetEvent waiter;
//The Main Method
public string CallLongOp()
{
// Set a manual reset which you can reset within your callback
waiter = new ManualResetEvent(false);
//Call the asynchronous operation
IAsyncResult result = longOpDelegate.BeginInvoke(Callback, null);
// Wait
waiter.WaitOne();
//return result saved in Callback
return longOpResult;
}
//The long operation
static void DoLongOp()
{
Thread.Sleep(5000);
}
//The Callback
void Callback(IAsyncResult result)
{
longOpResult = "Completed";
this.longOpDelegate.EndInvoke(result);
waiter.Set();
}
}
For the example you have given, you would be better not using a callback and instead handling the result in your CallLongOp function, in which case your WaitOne on the operation delegate will work fine.
The callback is executed after the CallLongOp method. Since you only set the variable value in the callback, it stands to reason that it would be null.
Read this :link text
I had the same issue recently, and I figured another way to solve it, it worked in my case. Bacially if the timeout doesn't borther you, re-check the flag IsCompleted when Wait Handle is timeout. In my case, the wait handle is signaled before blocking the thread, and right after the if condition, so recheck it after timeout will do the trick.
while (!AsyncResult.IsCompleted)
{
if (AsyncWaitHandle.WaitOne(10000))
break;
}

Queue a thread in .net

I have 2 functions that needs to be executed one after the other. In this function, async calls are made. How do I go about executing the second function after the async call is completed?
For eg.
public void main()
{
executeFn("1");
executeFn("2"); //I want this to be executed after 1 has finished.
}
private bool executeFn(string someval)
{
runSomeAsyncCode(); //This is some async uploading function that is yet to be defined.
}
You can use Thread.Join.
But then I do not see the point of async execution of those 2 functions as they become sequential.
Let runSomeAsyncCode() return an IAsyncResult and implement the BeginX EndX methods similar to the CLR Asynchronous Programming Model. Use the EndX method to wait for the code to finish executing.
Your async method you're calling must have something to notify the caller when it's completed am I correct? (otherwise it would be just execute and forget, which is unlikely) If so, you simply have to wait for the notification to come up and execute the second method.
try this:
public void main()
{
executeFn("1");
executeFn("2");
}
List<string> QueuedCalls = new List<string>(); // contains the queued items
bool isRunning = false; // indicates if there is an async operation running
private bool executeFn(string someval)
{
if(isRunning) { QueuedCalls.Add(someval); return; } // if there is an operation running, queue the call
else { isRunning = true; } // if there is not an operation running, then update the isRunning property and run the code
runSomeAsyncCode(); //undefined async operation here<-
isRunning = false; //get here when the async is completed, (updates the app telling it this operation is done)
if(QueuedCalls.Count != 0)//check if there is anything in the queue
{
//there is something in the queue, so remove it from the queue and execute it.
string val = QueuedCalls[0];
QueuedCalls.RemoveAt(0);
executeFn(val);
}
}
this way will not block any threads, and will simply execute the queued call when the first finnishs,which is what i believe you want! happy coding! now id recommend running the last section, at where it sets the isRunning to false, inside your async operation, or trigger it with an event or something, the only catch is that peice of code has to be executed when your async operation is completed, so however you want to do that is up to you
You can consider using Generic delegates execute the first method async then in the call back execute the other method async. If you are really worried executing them sync with respect to each other.
One simple way is to use a custom threadpool
http://www.codeplex.com/smartthreadpool
You can instantiate a separate threadpool, Set the threadpool size to 1, and queue the workers

Categories

Resources