I'm looking to implement a synchronous and asynchronous version of a method within a class library. Currently I've done this so that the Async method fires off a new Thread and does it's processing. To determine if the action has completed the user should poll a property to see if it has finished.
I'd like to improve it, I think it would be better to use some form of Async callback or result, but I'm not really sure how to go about implementing it, or, if indeed it is necessary. Can anyone offer any advice?
public static void Queue(Action action, Action done) {
ThreadPool.QueueUserWorkItem(_ =>
{
try {
action();
}
catch (ThreadAbortException) { /* dont report on this */ }
catch (Exception ex) {
Debug.Assert(false, "Async thread crashed! This must be fixed. " + ex.ToString());
}
// note: this will not be called if the thread is aborted
if (done != null) done();
});
}
Usage:
Queue( () => { Console.WriteLine("doing work"); },
() => { Console.WriteLine("work was done!"); } );
You can use a callback method instead of polling.
Check out my answer on AsyncCallback
Edited:
Example of FileCopy using own async delegates with callback:
public class AsyncFileCopier
{
public delegate void FileCopyDelegate(string sourceFile, string destFile);
public static void AsynFileCopy(string sourceFile, string destFile)
{
FileCopyDelegate del = new FileCopyDelegate(FileCopy);
IAsyncResult result = del.BeginInvoke(sourceFile, destFile, CallBackAfterFileCopied, null);
}
public static void FileCopy(string sourceFile, string destFile)
{
// Code to copy the file
}
public static void CallBackAfterFileCopied(IAsyncResult result)
{
// Code to be run after file copy is done
}
}
You can call it as:
AsyncFileCopier.AsynFileCopy("abc.txt", "xyz.txt");
Asynchronous Delegates could be another option.
Read about Asynchronous Programming Using Delegates on MSDN
Related
I need to call SendEmail() in my C# code below so that my program doesn't get blocked due to SendEmail() method taking a lot of time and or failing.
Here's my C# code:(I'm using .Net 4.5)
private void MyMethod()
{
DoSomething();
SendEmail();
}
Can I achieve the same using following please?Or is there any other better approach ?Is using async/await a better approach for achieving this?
public void MyMethod()
{
DoSomething();
try
{
string emailBody = "TestBody";
string emailSubject = "TestSubject";
System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(SendEmailAlert), arrEmailInfo);
}
catch (Exception ex)
{
//Log error message
}
}
private void SendEmailAlert(object state)
{
string[] arrEmailnfo = state as string[];
MyClassX.SendAlert(arrEmailnfo[0], arrEmailnfo[1]);
}
And In case I need to make SendEmailAlert() method as fire and forget, I can use code like this Would that be correct? ---->
Task.Run(()=> SendEmailAlert(arrEmailInfo));
Thanks.
Async await can definitely help you. When you have CPU-bound work to do asynchronously, you can use Task.Run(). This method can be "awaited" so that the code will resume after the task is done.
Here's what I would do in your case:
public async Task MyMethod()
{
DoSomething();
try
{
string emailBody = "TestBody";
string emailSubject = "TestSubject";
await Task.Run(()=> SendEmailAlert(arrEmailInfo));
//Insert code to execute when SendEmailAlert is completed.
//Be aware that the SynchronizationContext is not the same once you have resumed. You might not be on the main thread here
}
catch (Exception ex)
{
//Log error message
}
}
private void SendEmailAlert(string[] arrEmailInfo)
{
MyClassX.SendAlert(arrEmailnfo[0], arrEmailnfo[1]);
}
I'm using Async CTP to write an IO heavy console app. But I'm having problems with exceptions.
public static void Main()
{
while (true) {
try{
myobj.DoSomething(null);
}
catch(Exception){}
Console.Write("done");
//...
}
}
//...
public async void DoSomething(string p)
{
if (p==null) throw new InvalidOperationException();
else await SomeAsyncMethod();
}
And the following happens: "done" gets written to the console, then I get the exception in the debugger, then I press continue my program exists.
What gives?
If you give your Console application an async-compatible context (e.g., AsyncContext (docs, source) from my AsyncEx library), then you can catch exceptions that propogate out of that context, even from async void methods:
public static void Main()
{
try
{
AsyncContext.Run(() => myobj.DoSomething(null));
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.Message);
}
Console.Write("done");
}
public async void DoSomething(string p)
{
if (p==null) throw new InvalidOperationException();
else await SomeAsyncMethod();
}
When you call DoSomething() it basically creates a Task under the hood and starts that Task. Since you had a void signature, there is no Task object to signal back or that you could have blocked on, so execution fell straight through to done. Meanwhile the task throws an exception, which nobody is catching, which, I suspect, is why your program terminates.
I think the behavior you wanted is more like this:
public static void Main()
{
while (true) {
var t = myobj.DoSomething(null);
t.Wait();
if(t.HasException) {
break;
}
}
Console.Write("done");
//...
}
}
//...
public async Task DoSomething(string p)
{
if (p==null) throw new InvalidOperationException();
else await SomeAsyncMethod();
}
This will block on each DoSomething until it's done and exit the loop if DoSomething threw. Of course, then you are not really doing anything async. But from the pseudo code, i can't quite tell what you wanted to happen asynchronously.
Main take-away: Using void for an async method means that you loose the ability to get the exception unless you are awaiting that async method. As a sync call it basically just schedules work and the outcome disappears into the ether.
I've placed some very basic code below of what I'm trying to do. I have the 'DoSomethingAshnc' method that performs an Asynchronous operation. I would like the 'DoSomething' method to be a Synchronous method that doesn't take in the action parameter and returns an int.
public void DoSomething(Action<int> actionToPerformOnComplete)
{
DoSomethingAsync(delegate(int val)
{
actionToPerformOnComplete(val);
});
}
Is it even possible to have 'DoSomething' return an integer as if the method was happening synchronously?
You'd need to add something in the end of your sync method, to tell it to wait for the other call to finish. I'm assuming your async method will have an event on to tell the caller when it's finished.
If so then I'd suggest using something like a ManualResetEvent, waiting on it in your sync thread, and set it in the Finish event receiver for the async one.
Example:
public void DoSomething(Action<int> actionToPerformOnComplete)
{
ManualResetEvent mre = new ManualResetEvent(false);
DoSomethingAsync(delegate(int val)
{
try
{
actionToPerformOnComplete(val);
}
finally
{
mre.Set();
}
});
mre.WaitOne();
}
As others have mentioned, you need to wait for your async method to finish. To do that without passing that Action parameter to your method, use this code:
public int DoSomething()
{
int result;
ManualResetEvent mre = new ManualResetEvent(false);
DoSomethingAsync(val => {result = val; mre.Set(); });
mre.WaitOne();
return result;
}
This executes the async method, waits for it to finish and assigns the result to a local variable. This result is returned.
Yes. All you have to do is to put this line of code:
IAsyncResult asycn = ... // make a call to Async and get back IAsyncResult
while(!asycn.IsCompleted)
{
Thread.Sleep( ....);
}
UPDATE
Just as some asked, a correctly designed async operation will implement async pattern MSDN:
An asynchronous operation that uses
the IAsyncResult design pattern is
implemented as two methods named
BeginOperationName and
EndOperationName that begin and end
the asynchronous operation
OperationName respectively. For
example, the FileStream class provides
the BeginRead and EndRead methods to
asynchronously read bytes from a file.
These methods implement the
asynchronous version of the Read
method.
using System;
using System.Threading;
namespace qqq
{
class Program
{
public static void DoAsync(Action<int> whenDone)
{
new Thread(o => { Thread.Sleep(3000); whenDone(42); }).Start();
}
static public int Do()
{
var mre = new ManualResetEvent(false);
int retval = 0;
DoAsync(i => { retval = i; mre.Set(); });
if (mre.WaitOne())
return retval;
throw new ApplicationException("Unexpected error");
}
static void Main(string[] args)
{
Console.WriteLine(Do());
}
}
}
Why does the delegate need to call the EndInvoke before the method fires? If i need to call the EndInvoke (which blocks the thread) then its not really an asynchronous call is it?
Here is the code im trying to run.
class Program
{
private delegate void GenerateXmlDelegate();
static void Main(string[] args)
{
GenerateXmlDelegate worker = new GenerateXmlDelegate(GenerateMainXml);
IAsyncResult result = worker.BeginInvoke(null, null);
}
private static void GenerateMainXml()
{
Thread.Sleep(10000);
Console.WriteLine("GenerateMainXml Called by delegate");
}
}
The reason you need to call EndInvoke is to avoid memory leaks; .Net will store information about the function's result (or exception) until you call EndInvoke.
You can call EndInvoke in the completion handler that you give to BeginInvoke and retain the asyncronous nature.
EDIT:
For example:
class Program {
private delegate void GenerateXmlDelegate();
static void Main(string[] args) {
GenerateXmlDelegate worker = new GenerateXmlDelegate(GenerateMainXml);
IAsyncResult result = worker.BeginInvoke(delegate {
try {
worker.EndInvoke();
} catch(...) { ... }
}, null);
}
private static void GenerateMainXml() {
Thread.Sleep(10000);
Console.WriteLine("GenerateMainXml Called by delegate");
}
}
If you want to fire an async call and forget about it, you can use the ThreadPool, like this:
ThreadPool.QueueUserWorkItem(delegate { GenerateMainXml(); });
As SLaks said, EndInvoke insures against memory leaks.
BeginInvoke is still asynchronous; consider the following code:
static void Main() {
Func<double> slowCalculator = new Func<double>(PerformSlowCalculation);
IAsyncResult slowCalculation = slowCalculator.BeginInvoke(null, null);
// lots of stuff to do while slowCalculator is doing its thing
Console.WriteLine("Result is {0}", slowCalculator.EndInvoke(slowCalculation));
}
static double PerformSlowCalculation() {
double result;
// lots and lots of code
return result;
}
If this code were written without the BeginInvoke/EndInvoke calls, PerformSlowCalculation would have to finish before Main could do the rest of its "lots of stuff"; this way, the two can be happening at the same time.
Now, in your example using a GenerateXmlDelegate, you still need EndInvoke even though you're not returning anything. The way to do this is:
static void Main(string[] args) {
GenerateXmlDelegate worker = new GenerateXmlDelegate(GenerateMainXml);
IAsyncResult result = worker.BeginInvoke(GenerateXmlComplete, null);
}
private static void GenerateXmlComplete(IAsyncResult result) {
AsyncResult realResult = result as AsyncResult;
GenerateXmlDelegate worker = result.AsyncDelegate as GenerateXmlDelegate;
worker.EndInvoke();
}
I've a RichTextBox which I use as output from a custom TraceListener shown below:
The trouble is this seems to deadlock hard if anyone is writing debug/trace info from other
threads while a GUI dialog also is trying to write debug/trace info.
Anyone care to point at some obvious errors here ? :
class MyTraceListener : TraceListener
{
private RichTextBox output;
public MyTraceListener (RichTextBox output) {
this.Name = "DebugTrace";
this.output = output;
}
public override void Write(string message) {
Action append = delegate() { output.AppendText(message); };
if (output.InvokeRequired) {
IAsyncResult result = output.BeginInvoke(append);
output.EndInvoke(result);
} else {
append();
}
}
public override void WriteLine(string message) {
Action append = delegate() { output.AppendText(message + "\r\n"); };
if (output.InvokeRequired) {
IAsyncResult result = output.BeginInvoke(append);
output.EndInvoke(result);
} else {
append();
}
}
}
Here's what's likely happening:
Thread 1: Gets to EndInvoke();
waiting to execute the delegate in
the GUI thread.
GUI thread: is blocking in
System.Diagnostics.Trace.WriteLine
somewhere (afaik the trace system
employs locks to be thread safe.)
Thread 1: will block forever, since the GUI thread is blocked and can't finish executing the delegate.
Calling just Invoke will likely not solve the problem, since Invoke blocks until the delegate is done running.
Calling only BeginInvoke should solve the locking, BeginInvoke will just initiate an asynchronous call to the GUI thread, not waiting till it's finished thus leaving the trace system and unblock the GUI thread. (I'm not sure about the ramification of not calling EndInvoke though.
I would advise you to use a simple producer/consumer queue here. Your response to the trace write should be to add the string to a queue, then in the form displaying the data you can use a System.Windows.Forms.Timer() to empty the queue and display the text. Otherwise you are going to encounter issues and/or delays in the running program.
Just a thought, try using Control.Invoke as opposed to BeginInvoke. IE:
class MyTraceListener : TraceListener
{
private RichTextBox output;
public MyTraceListener (RichTextBox output) {
this.Name = "DebugTrace";
this.output = output;
}
public override void Write(string message) {
Action append = delegate() { output.AppendText(message); };
if (output.InvokeRequired) {
output.Invoke(append);
} else {
append();
}
}
public override void WriteLine(string message) {
Action append = delegate() { output.AppendText(message + "\r\n"); };
if (output.InvokeRequired) {
output.Invoke(append);
} else {
append();
}
}
}
What if you try using this approach?
public override void Write(string message) {
if (this.output.InvokeRequired)
{
this.output.Invoke((MethodInvoker)delegate
{
this.output.AppendText(message);
});
}
else
{
this.output.AppendText(message);
}
}