Why does asynchronous delegate method require calling EndInvoke? - c#

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();
}

Related

Implementing Your ThreadPool

A ThreadPool is created that does all the work on one thread and notifies when the work is done. The thread is started and the methods Execute1 and Execute2 are not displayed, but Done1 and Done2 are not displayed, although in the debugger execution reaches handle.Finished.
public class MyThreadPool
{
private readonly Thread[] _Threads;
public delegate void ParameterizedThreadStart(object? obj);
public MyThreadPool()
{
_Threads = new Thread[1];
}
public HandleEvent QueueUserWorkItem(System.Threading.ParameterizedThreadStart callBack)
{
var thread = new Thread(callBack) { IsBackground = true };
_Threads[0] = thread;
_Threads[0].Start();
return new HandleEvent();
}
}
public class HandleEvent : EventArgs
{
public event EventHandler? Finished;
protected virtual void onFinished(object e, EventArgs s)
{
Finished?.Invoke(this, EventArgs.Empty);
}
public HandleEvent ()
{
onFinished("sddd", EventArgs.Empty);
}
}
public static class Program
{
public static void Main()
{
static void ExecuteMethod2(object execute)
{
Console.WriteLine("Hello from the thread pool.");
}
static void ExecuteMethod1(object execute)
{
Console.WriteLine("Hello from the thread pool.");
}
var thread_pool = new MyThreadPool();
var handle1 = thread_pool.QueueUserWorkItem(ExecuteMethod1);
handle1.Finished += (o, a) => { Console.WriteLine($"Done 1"); };
var handle2 = thread_pool.QueueUserWorkItem(ExecuteMethod2);
handle2.Finished += (o, a) => { Console.WriteLine($"Done 2"); };
}
}
The problem is that the onFinished method is never called. This should be called once the thread has completed execution of its callback, but it is not. For this to work the QueueUserWorkItem needs to wrap the callback in a method that does this, i.e. something like
var result = new HandleEvent();
void localExecute(object execute)
{
callBack(execute); // run the actual work
result.onFinished(); // Raise the finished method
}
var thread = new Thread(localExecute) { IsBackground = true };
_Threads[0] = thread;
_Threads[0].Start();
return result ;
However, there are other issues:
There is no actual thread pooling going on. The point of a threadpool is that threads are expensive to create, so you keep them around in a pool instead of creating new ones. The threads should be in a blocked state while in the pool, so the pool can assign the thread a task and wake it when needed.
There is no synchronization going on, so the program may very well complete before all threads are done. So you may want to return something like a ManualResetEvent that can be waited on, instead of your own custom event.
There is rarely any reason to implement your own thread pool, and doing so well is quite difficult. So I really hope you are doing this for educational purposes, and do not intend to use the result in real life.

C# async method call

I would have a async call to a function as following:
I'll call a method from the main method, this function should be async, how I do this?
A little example:
private static void Main(string[] args)
{
StartDoingNothingAsync();
Console.WriteLine("test");
Console.Read();
}
private static async void StartDoingNothingAsync()
{
for (var i = 0; i < 5000; i++)
{
//do something
}
Console.WriteLine("leaved");
}
I would first the output "test", before "leaved", how can I practice this?
The simplest option would be to introduce a delay into your async method:
private static async void StartDoingNothingAsync()
{
await Task.Delay(1000);
// This will be called on a thread-pool thread
Console.WriteLine("leaved");
}
That won't guarantee that test will be printed before leaved, but it seems very likely. If you actually want a guarantee, you'd have to pass something into StartDoingNothingAsync that you then signal after printing test... but it's not really clear what you're trying to achieve.
Note that async methods should almost never be void - basically that's only available to allow for async event handlers. Make the method return Task instead - that way your calling code can tell when it's completed. (Even if you don't use that fact in this case, it's a good habit to get into.)
Now that we have a bit more information about what you're trying to achieve, I would recommend not making StartDoingNothingAsync an async method - just use a task instead:
private static void Main(string[] args)
{
Task task = Task.Run(DoSomething);
Console.WriteLine("test");
task.Wait();
Console.Read();
}
static void DoSomething()
{
// Code to run on a separate thread
}
You can do it like this
private static void Main(string[] args)
{
StartDoingNothingAsync();
Console.WriteLine("test");
Console.Read();
}
private static async void StartDoingNothingAsync()
{
await Task.Run(async delegate()
{
for (var i = 0; i < 5000; i++)
{
//do something
}
Console.WriteLine("leaved");
});
}
You can use Task for that. In that case you don't need to mark your function as async:
private static void Main(string[] args)
{
new Task(StartDoingNothing).Start();
Console.WriteLine("test");
Console.Read();
}
private static void StartDoingNothing()
{
for (var i = 0; i < 5000; i++)
{
//do something
}
Console.WriteLine("leaved");
}

Delegate.BeginInvoke Callback Blocking Calling Thread?

I'm not really sure where to look with this problem as I'm not particularly familiar with asynchronous programming. I have a loop which invokes a delegate's BeginInvoke method. When the delegate's callback is executed the loop ceases to execute (it shouldn't). I'm guessing that somehow the thread it's running on is being blocked but I really don't know for sure. Here's a simplified version of the code:
public class TestClass
{
private readonly IService service;
private delegate void TestDelegate();
private bool conditionIsMet = true;
public TestClass( IService service )
{
this.service = service;
}
public void PerformTask()
{
while ( conditionIsMet )
{
var testDelegate = new TestDelegate( service.DoSomething );
testDelegate.BeginInvoke( TestCallback, null );
Thread.Sleep( 1 );
}
}
private void TestCallback( IAsyncResult result )
{
var asyncResult = ( AsyncResult ) result;
var testDelegate = ( TestDelegate ) asyncResult.AsyncDelegate;
testDelegate.EndInvoke( asyncResult );
// After exiting this method the loop in PerformTask() ceases to execute.
// Is it being blocked here somehow?
}
}
In practice there is a bit more to the code but the essential components involved are all here so far as I can tell. In the code sample above I've put a comment in there to indicate the last place the code executes (in the VS debugger, anyway).
I assume that I'm making some sort of fundamental error in the way I'm doing the delegate async invocation but I can't find any docs that explain it to me. Any idea why this is happening?
UPDATE
As part of further testing, I tried this without the EndInvoke call (I know, bad idea in practice) but there was no change in behaviour - it still failed to continue executing the loop.
It works ok for me I think. Are you running it in a console application?
You would need to stop that exiting.
class Program
{
static void Main(string[] args)
{
TestClass t = new TestClass(new Service());
t.PerformTask();
Console.ReadKey();
}
}
public class Service : IService
{
public void DoSomething()
{
Console.WriteLine("Doing something");
}
}
public class TestClass
{
private readonly IService service;
private delegate void TestDelegate();
private bool conditionIsMet = true;
public TestClass(IService service)
{
this.service = service;
}
public void PerformTask()
{
while (conditionIsMet)
{
var testDelegate = new TestDelegate(service.DoSomething);
testDelegate.BeginInvoke(TestCallback, null);
Thread.Sleep(1);
}
}
private void TestCallback(IAsyncResult result)
{
var asyncResult = (AsyncResult)result;
var testDelegate = (TestDelegate)asyncResult.AsyncDelegate;
testDelegate.EndInvoke(asyncResult);
// After exiting this method the loop in PerformTask() ceases to execute.
// Is it being blocked here somehow?
}
}
public interface IService
{
void DoSomething();
}

Creating a new background thread each time I invoke specific method

WinForm:
I have a method called check_news in my MainApplication.
How can I create and run a Thread that will work on the method on background each time I call the method (by pushing a button, or in the start of the program)?
I know how to create a thread but how can I create new thread every time I call the function (new thread because the old one is dead)?
Should I create a new class and run the thread with the new class object and the method I need?
Where should I define the thread?
public void Example()
{
//call using a thread.
ThreadPool.QueueUserWorkItem(p => check_news("title", "news message"));
}
private void check_news(string news, string newsMessage)
{
}
You can just create a thread inside the method by writing new Thread(...).
The ... can be a method name, delegate instance, or anonymous method.
Each time this code executes, it will create a new Thread instance.
Note that it will be more efficient to use the ThreadPool instead.
I suppose the best way to achieve this is by adding it to the thread pool, it's easy and quick.
Example:
public static void Main(string[] args)
{
check_news();
}
private static void check_news()
{
ThreadPool.QueueUserWorkItem((obj) =>
{
// Fetch the news here
Thread.Sleep(1000); // Dummy
});
}
Or if you really want to deal with it yourself, this is something you could use:
public static void Main(string[] args)
{
check_news();
Console.ReadKey();
}
private static void check_news()
{
Thread t = new Thread(() =>
{
// Check news here
Thread.Sleep(1000); // Dummy
});
t.Priority = ThreadPriority.Lowest; // Priority of the thread
t.IsBackground = true; // Set it as background (allows you to stop the application while news is fetching
t.Name = "News checker"; // Make it recognizable
t.Start(); // And start it
}
But you should know that this takes a longer time to start, it doesn't reuse threads, and there's not a real advantage in it.
Or if you want more control you could use the async platform:
public static void Main(string[] args)
{
check_news(); // You can add an argument 'false' to stop it from executing async
Console.WriteLine("Done");
Console.ReadKey();
}
public delegate void Func();
public static void check_news(bool async = true)
{
Func checkNewsFunction = () =>
{
//Check news here
Thread.Sleep(1000);
};
if (async)
{
AsyncCallback callbackFunction = ar =>
{
// Executed when the news is received
};
checkNewsFunction.BeginInvoke(callbackFunction, null);
}
else
checkNewsFunction();
}
Note that the lambda expressions in all examples can just as well be replaced by regular functions. But I just use them right now, because it seems nicer as example.

Is it possible to call an Asynchronous call Synchronously?

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());
}
}
}

Categories

Resources