locked
Issue with delegate.BeginInvoke / EndInvoke RRS feed

  • Question

  • I've got a reproducable issue where my tests hang (ie freeze forever, rather than chess detecting a deadlock) when I use delegate.BeginInvoke/EndInvoke as part of my test.

    The strange thing is that I've written a series of trivial tests for each of the parts in the test, and they work fine, it's only when I put all the pieces together that Chess appears to lose the plot. It's the delegate, in my helper class, via a lamda, in my workflow class :-(

    When I replace the delegate with a structure that achieves the same thing (ie wrap the execution of a delegate on a ThreadPool.QueueUserWorkItem thread and expose it using a Begin/End API) all works fine. So there's definately something fishy going on that's not just due to all my cruft around. And, like I say, the trivial test against BeginInvoke/EndInvoke works fine in isolation.

    Whilst I've got a repro, it's not small. Where do I go from here? Have I got some kind of instrumentation problem, where the delegate's not being 'seen' by chess due to the complexity of the surrounding code?

    Tuesday, July 20, 2010 11:57 AM

All replies

  • There's a known problem with CHESS and [Begin/End]Invoke involving AsyncResult

    http://msdn.microsoft.com/en-us/library/system.runtime.remoting.messaging.asyncresult.aspx

    which implements IAsyncResult but also has other various features (requiring you to downcast the  IAsyncResult returned from BeginInvoke to AsyncResult - ick).  If you are making use of methods particular to AsyncResult, bad things can happen.  We have tested CHESS (minimally) on vanilla BeginInvoke/EndInvoke, like the code below.

    -- Tom

    using System;
    using System.Threading;

    namespace Examples.AdvancedProgramming.AsynchronousOperations
    {

    public class ChessTest {

      // the regular test entry point
      public static void Main(string [] s) {
           Run();
      }

      public static bool Run() {
         return AsyncMain.Main2();
      }

    }

        public class AsyncDemo
        {
            // The method to be executed asynchronously.
            public string TestMethod(int callDuration, out int threadId)
            {
                Thread.Sleep(1);
                threadId = Thread.CurrentThread.ManagedThreadId;
                return String.Format("{0}", threadId);
            }
        }
        // The delegate must have the same signature as the method
        // it will call asynchronously.
        public delegate string AsyncMethodCaller(int callDuration, out int threadId);

        public class AsyncMain
        {
            public static bool Main2()
            {
                // The asynchronous method puts the thread id here.
                int threadId;

                // Create an instance of the test class.
                AsyncDemo ad = new AsyncDemo();

                // Create the delegate.
                AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

                // Initiate the asychronous call.
                IAsyncResult result = funnyhelper(caller,out threadId);

                Thread.Sleep(0);

                // Call EndInvoke to wait for the asynchronous call to complete,
                // and to retrieve the results.
                string returnValue = caller.EndInvoke(out threadId, result);

                bool flag = (threadId == Convert.ToInt32(returnValue));
                return flag;
            }

     public static IAsyncResult funnyhelper(AsyncMethodCaller caller, out int tid) {
                 try {
                   return caller.BeginInvoke(3000, out tid, null, null);
                 } catch (Exception) {
                   tid = 0;
                   return null;
                 }
            }
        }
    }

    Wednesday, July 21, 2010 1:02 AM
  • I wasn't casting to AsyncResult (didn't even know you could actually), so presumably I wasn't using any of the AsyncResult-specific methods: just the IAsyncResult implementation.

    Like I said, my trivial Begin/End test works fine, but when I embed the same logic in a much larger test it fails. I wonder what the smallest repro I can produce is...

    Wednesday, August 4, 2010 12:39 AM