I need to use callback function to do some post procesing tasks when the function started with the Dispatcher.BeginInvoke finishes. However i could not find any parameter in Dispatcher.BeginInvoke to accept a callback. Is it possible to give a callback function to Dispatcher.BeginInvoke?
The DispatcherOperation object returned by BeginInvoke has a Completed event on it. Subscribe to that to perform operations upon completion:
var dispatcherOp = Dispatcher.BeginInvoke( /* your method here */);
dispatcherOp.Completed += (s, e) => { /* callback code here */ };
There's a chance the operation will complete before you subscribe, so you can test the Status property for completion after as well:
if (dispatcherOp.Status == DispatcherOperationStatus.Completed) { ... }
It's possible for the operation to be aborted as well, so handling/testing for Aborted may also be appropriate.
Related
Sometimes I need to start an async job which works very slow. I don't care if that job success and I need to continue working on my current thread.
Like sometimes I need to send an Email or SMS which works very slow. I need to respond to the web client as soon as possible so I don't want to await it.
I have googled this question and some articles suggest me to write like this:
// This method has to be async
public async Task<Response> SomeHTTPAction()
{
// Some logic...
// ...
// Send an Email but don't care if it successfully sent.
Task.Run(() => _emailService.SendEmailAsync());
return MyRespond();
}
Or like this:
// This method has to be async
public async Task<Response> SomeHTTPAction()
{
// Some logic...
// ...
// Send an Email but don't care if it successfully sent.
Task.Factory.StartNew(() => _emailService.SendEmailAsync());
return MyRespond();
}
There will be a warning says: before the call is completed. Consider applying the 'await' operator to the result of the call.
So what if I really awaited it? What is the best practice in C# to 'fire and forget', just call an async method without waiting for its completion?
A standalone discard is the best way to avoid this warning.
_ = Task.Run(() => _emailService.SendEmailAsync());
Discards are dummy variables and can be used to ignore the Task object returned by an asynchronous operation.
https://learn.microsoft.com/en-us/dotnet/csharp/discards#a-standalone-discard
If you truly just want to fire and forget. Simply don't call use await.
// It is a good idea to add CancellationTokens
var asyncProcedure = SomeHTTPAction(cancellationToken).ConfigureAwait(false);
// Or If not simply do:
var asyncProcedure = SomeHTTPAction().ConfigureAwait(false);
If you want to use the result output later its gets trickier. But if it is truly fire and forget the above should work
A Cancellation token allows interrupts and canceling procedures. If you are using Cancellation token you will need to use it everywhere from the retrieval straight through to the calling method (Turtles all the way down).
I used ConfigureAwait(false) to prevent deadlocks. Here for more information
EDIT
See the second answer that uses 'Task.Factory.StartNew' I gave this answer some time ago. At the time I didn't realise that the way I did it at the time doesn't ensure completion.
If you need to use async in your function you can also use a discard variable and don't use await. This is also usefull if you have multiple async function calls but you don't need to wait for all of them.
public async function(){
var tmp = await asyncfunction();
...
_ = _httpClient.PutAsync(url, content);
...
}
As Amadan told in the comment that, you need to remove async from your function. then it will stop giving you the warning.
// This method has to be async
public Response SomeHTTPAction()
{
// Some logic...
// ...
// Send an Email but don't care if it successfully sent.
Task.Factory.StartNew(() => _emailService.SendEmailAsync());
return MyRespond();
}
and Task.Factory.StartNew(() => _emailService.SendEmailAsync()); will indeed work on a new thread.
It all depends on what your Async method accepts. Normally it will accept a "special" class that also holds an event. You can subscribe your callback method to that event and pass it along with the method. When it's finished, your callback method will be called.
An example of this (for sockets) would be:
public void CreateSocket()
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
SocketAsyncEventArgs sockAsync = new SocketAsyncEventArgs();
sockAsync.Completed += SockAsync_Completed;
s.ConnectAsync(sockAsync);
}
private void SockAsync_Completed(object sender, SocketAsyncEventArgs e)
{
//Do stuff with your callback object.
}
It all depends on what the method you are trying to call can accept. I would look at the documentation for more help on that specifically.
I am curious why this hasn't been suggested.
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
//what ever code here...e.g.
DoSomething();
UpdateSomething();
}).Start();
It just fires off a separate thread.
How could I call the onCompleteCallBack method on the same thread the SomeAsyncMethod was called ?
public void SomeAsycMethod ( Action<object> onCompleteCallBack )
{
// get the current thread
/* var ThisThread = Thread.CurrentThread. */
Task.Factory.StartNew( () =>
{
Thread.Sleep( 1000 );// do some work;
// lastly call the onCompleteCallBack on 'ThisThread'
onCompleteCallBack( "some result" );
// I am looking for something like:
/* ThisThread.Invoke("some result"); */
});
}
While you can't guarantee you callback will be called on the same thread, you can guarantee it will be called in the same Synchronization Context (assuming one exists in the original call).
public void SomeAsycMethod ( Action<object> onCompleteCallBack )
{
// get the current context
var context = SynchronizationContext.Current;
Task.Factory.StartNew( () =>
{
Thread.Sleep( 1000 );// do some work;
// lastly call the onCompleteCallBack on 'ThisThread'
onCompleteCallBack( "some result" );
// I am looking for something like:
context.Post(s => onCompleteCallBack ("some result"), null);
});
}
For example, in a Windows Forms or WPF program, the above will make sure that the callback is called on the GUI thread (via the message loop or dispatcher, accordingly). Similarly for ASP.NET context.
Having said that, I agree with Justin Harvey in that returning a Task<T> will probably be a better design.
Actually if you're using Task-based asynchronous programming I suggested you refactor your code to return Task<T> and give an ability to your client itself to decide in what context to call callback method (and facilitate future migration to C# 5.0 ;):
public Task<string> SomeMethodAsync()
{
return Task.Factory.StartNew(() => "some result");
}
If you definitely know that you're going to call this method from UI thread you can use following:
var task = SomeMethodAsync();
task.ContinueWith(t => textBox.Text = t.Result, TaskScheduler.FromSynchronizationContext);
This approach is better because it provide more clear separation of concern and give an ability to use your asynchronous method in any context without any dependencies to synchronization context. Some client can call this method from UI thread (and in this case TaskScheduler.FromSynchronizationContext would behave as expected - your "continuation" would be called in UI thread), some of them could use your method from non-UI thread as well without such requirements like processing results in the same thread that initiate asynchronous operation.
Task<T> is a perfect class that represents asynchronous operation as a first class object that helps not only obtain only more declarative code but more clear, easy to read and easy to test (you can easily mock this method and return "fake" task object).
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
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;
}
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