5

I'm trying to write a really simple bit of async code. I have a void method that doesn't take any parameters, which is to be called from a Windows service. I want to kick it off async, so that the service doesn't have to hang around waiting for the method to finish.

I created a very simple test app to make sure I was doing the coding right, but the async method just isn't being called. Anyone able to see what I've done wrong? I'm using .NET 4.0 by the way, so I can't use await (which would be a whole lot simpler!).

Here is my entire test sample...

using System;
using System.Threading;

namespace AsyncCallback {
  internal class Program {
    private static void Main(string[] args) {
      Console.WriteLine(DateTime.Now.ToLocalTime().ToLongTimeString() + " - About to ask for stuff to be done");
      new Action(DoStuff).BeginInvoke(ar => StuffDone(), null);
      Console.WriteLine(DateTime.Now.ToLocalTime().ToLongTimeString() + " - Asked for stuff to be done");
    }

    private static void StuffDone() {
      Console.WriteLine(DateTime.Now.ToLocalTime().ToLongTimeString() + " - Stuff done");
    }

    private static void DoStuff() {
      Console.WriteLine(DateTime.Now.ToLocalTime().ToLongTimeString() + " - Starting to do stuff");
      Thread.Sleep(1000);
      Console.WriteLine(DateTime.Now.ToLocalTime().ToLongTimeString() + " - Ending doing stuff");
    }
  }
}

Thanks for any help you can give.

wkl
  • 77,184
  • 16
  • 165
  • 176
Avrohom Yisroel
  • 8,555
  • 8
  • 50
  • 106
  • @Martin : where's the `async`/`await` in the question above? – spender Dec 10 '12 at 19:26
  • @spender He was using "async" as the general purpose abbreviation for "asynchronous" as opposed to the C# keyword. – Servy Dec 10 '12 at 19:33
  • 1
    By the way instead of using a delegate (Action) you could use the ThreadPool.QueueUserWorkItem or even better you could get to know the types in System.Threading.Tasks namespace. It will be a better investment of your time. – Panos Rontogiannis Dec 10 '12 at 20:32
  • Rafael, I'm not using .NET 4.5 because the server where the real code will be deployed doesn't have it installed. – Avrohom Yisroel Dec 10 '12 at 20:33

4 Answers4

6

Your program is terminating before the async method gets deployed in the ThreadPool. Keep your program open for a bit. Perhaps Console.ReadKey() at the end of Main?

spender
  • 117,338
  • 33
  • 229
  • 351
  • Duh, obvious really! Thanks for that. I was doing this in a test project, so didn't have anything else happening after the async call. Forgot that the thread would end completely. Thanks. – Avrohom Yisroel Dec 10 '12 at 20:34
5

Any application will end as soon as there are no foreground threads that haven't completed execution. If there are any background threads they will not keep the process "alive".

Because you're starting the async task in the background, and nothing is keeping the foreground thread running, the entire process is exiting.

You either need to run your asynchronous task in a foreground thread instead (which can't be done with BeginInvoke as far as I know, you'd need to create a new Thread explicitly) or do something else to block the main thread until it finishes.

Servy
  • 202,030
  • 26
  • 332
  • 449
1

You are not waiting for completion, so try something like this

 Console.WriteLine(DateTime.Now.ToLocalTime().ToLongTimeString() + " - About to ask for stuff  to be done");
 var a = new Action(DoStuff);
 var iar = a.BeginInvoke(ar => StuffDone(), null);
 a.EndInvoke(iar);
 Console.WriteLine(DateTime.Now.ToLocalTime().ToLongTimeString() + " - Asked for stuff to be done");
Kleinux
  • 1,511
  • 10
  • 22
  • although if you're going to just wait on the results of the async task, why start it asynchronously in the first place... – Servy Dec 10 '12 at 19:32
1

To start off with, your callback is not the correct delegate... It should be

public delegate void AsyncCallback(IAsyncResult ar);

And yours is

private static void StuffDone()

Just change it to something like this:

private static void StuffDone(IAsyncResult ar){}

And then in your call back make sure that the Action actually executes by calling

EndInvoke

on the AsyncState

Like this:

private static void StuffDone(IAsyncResult ar)
{
    Action r = ar.AsyncState as Action;
    r.EndInvoke(ar);

    Console.WriteLine(DateTime.Now.ToLocalTime().ToLongTimeString() + " - Stuff done");
}

One more change you need to make is, when you instantiate the Action in the main function, pass the action itself as the 'object' argument of the BeginInvoke method like this:

Action d = new Action(DoStuff);
d.BeginInvoke(StuffDone, d);

this ought to solve your problem :)

mnemonic
  • 692
  • 1
  • 9
  • 18