views:

1358

answers:

5

I saw in WCF they have the [OperationContract(IsOneWay = true)] attribute. But WCF seems kind of slow and heavy just to do create a nonblocking function. Ideally there would be something like static void nonblocking MethodFoo(){}, but I don't think that exists.

What is the quickest way to create a nonblocking method call in c#?

E.g.

class Foo
{
    static void Main()
    {
        FireAway(); //No callback, just go away
        Console.WriteLine("Happens immediately");
    }

    static void FireAway()
    {
        System.Threading.Thread.Sleep(5000);
        Console.WriteLine("5 seconds later");
    }
}
+28  A: 

ThreadPool.QueueUserWorkItem(o => FireAway());

Will
You win. No, really, this seems to be the shortest version, unless you encapsulate that into another function.
OregonGhost
Thinking about this... in most applications this is fine, but in yours the console app will exit before FireAway sends anything to the console. ThreadPool threads are background threads and die when the app dies. On the other hand, using a Thread wouldn't work either as the console window would disappear before FireAway tried to write to the window.
Will
There is no way to have a non-blocking method call that is guaranteed to run, so this is in fact the most accurate answer to the question IMO. If you need to guarantee execution then potential blocking needs to be introduced via a control structure such as AutoResetEvent (as Kev mentioned)
Guvante
+1 This syntax is hard to find searching for parameterless lambdas
Maslow
To run the task in a thread independent of the thread pool, I believe you could also go `(new Action(FireAway)).BeginInvoke()`
280Z28
@280Z28 the only problem with that approach is any Exceptions that occur will be gobbled until you call EndInvoke. Seeing as you haven't kept a reference to the Action you'll never be able to call EndInvoke.
DoctaJonez
@Docta um, 1) he asked for "fire and forget". You're pointing out that it forgets. Yes, it does. That's what OP asked for. Not "Fire and remember." 2) there is no BeginInvoke/EndInvoke here. Its just running on a background thread. This has absolutely nothing to do with the APM.
Will
@Will, I was just pointing out the major pitfall with calling BeginInvoke without a matching EndInvoke. That's not fire and forget, that's fire and cross your fingers! ;-)
DoctaJonez
@Docta I completely misinterpreted your comment as a reply to my answer! I feel like a complete heel. Excuse me for my stupidity. You are, of course, absolutely right about @280's comment. To call BeginInvoke and not call EndInvoke leaks resources and swallows exceptions.
Will
+4  A: 

An easy way is to create and start a thread with parameterless lambda:

(new Thread(() => { 
    FireAway(); 
    MessageBox.Show("FireAway Finished!"); 
}) { 
    Name = "Long Running Work Thread (FireAway Call)",
    Priority = ThreadPriority.BelowNormal 
}).Start();

By using this method over ThreadPool.QueueUserWorkItem you can name your new thread to make it easier for debugging. Also, don't forget to use extensive error handling in your routine because any unhandled exceptions outside of a debugger will abruptly crash your application:

Robert Venables
+8  A: 

To add to Will's answer, if this is a console application, just throw in an AutoResetEvent and a WaitHandle to prevent it exiting before the worker thread completes:

Using System;
Using System.Threading;

class Foo
{
    static AutoResetEvent autoEvent = new AutoResetEvent(false);

    static void Main()
    {
     ThreadPoolQueueUserWorkItem(new WaitCallback(FireAway), autoEvent);
     autoEvent.WaitOne(); // Will wait for thread to complete
    }

    static void FireAway(object stateInfo)
    {
     System.Threading.Thread.Sleep(5000);
     Console.WriteLine("5 seconds later");
     ((AutoResetEvent)stateInfo).Set();
    }
}
Kev
A: 

The simplest .NET 2.0 and later approach is using the Asynchnonous Programming Model (ie. BeginInvoke on a delegate):

static void Main(string[] args)
{
      new MethodInvoker(FireAway).BeginInvoke(null, null);

      Console.WriteLine("Main: " + Thread.CurrentThread.ManagedThreadId);

      Thread.Sleep(5000);
}

private static void FireAway()
{
    Thread.Sleep(2000);

    Console.WriteLine("FireAway: " + Thread.CurrentThread.ManagedThreadId );  
}
Ash
A: 

Calling beginInvoke and not catching EndInvoke is not a good approach. Answer is simple: The reason that you should call EndInvoke is because the results of the invocation (even if there is no return value) must be cached by .NET until EndInvoke is called. For example if the invoked code throws an exception then the exception is cached in the invocation data. Until you call EndInvoke it remains in memory. After you call EndInvoke the memory can be released. For this particular case it is possible the memory will remain until the process shuts down because the data is maintained internally by the invocation code. I guess the GC might eventually collect it but I don't know how the GC would know that you have abandoned the data vs. just taking a really long time to retrieve it. I doubt it does. Hence a memory leak can occur.

More can be found on http://haacked.com/archive/2009/01/09/asynchronous-fire-and-forget-with-lambdas.aspx

Manoj Aggarwal