static void Main(string[] args)
        {
            Console.WriteLine("Main Thread:" + Thread.CurrentThread.ManagedThreadId);
            Action action = Method;
            try
            {
               IAsyncResult ir= action.BeginInvoke(CallBack, null);
               action.EndInvoke(ir);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.ReadKey();
        }        static void Method()
        {
            Console.WriteLine("Mehtod called in Thread:" + Thread.CurrentThread.ManagedThreadId);
            throw new Exception("Mehtod Exception in Thread:" + Thread.CurrentThread.ManagedThreadId);
        }        static void CallBack(IAsyncResult ir)
        {
            Console.WriteLine("CallBack called in Thread:" + Thread.CurrentThread.ManagedThreadId);
            //throw new Exception("CallBack Exception in Thread:" + Thread.CurrentThread.ManagedThreadId);
           
        }
大体我有上面这样的一段代码,Method方法用通过BeginInvoke异步调用,假设Main方法在线程1上运行,Method方法在线程2上运行。当Mehtod方法在线程2上抛出异常后,线程1可以catch到这个异常(当然线程1要调用EndInvoke)。小弟有如下几个问题想求大家帮忙解释下,
第一:那回调方法CallBack是否理论也在线程2上被调用,就是线程2执行完Method方法后就执行回调方法CallBack,还是CallBack可能在另外的线程上被调用?(我程序跑下来的显示结果是:在同一线程上运行)
第二:如果回调方法CallBack在线程2上被调用,那为什么CallBack抛出异常,线程1无法catch到,而且程序直接就崩溃了?
第三:如果回调方法CallBack不在线程2上被调用,而是在另外的新线程上调用,抛错了,那我怎么处理?能把异常抛给线程1吗?
第四:为什么在如上代码中,即使Method方法抛错,回调函数依然执行?
麻烦给位大哥指点迷津,小弟学多线程,各种概念,不是越学越清晰,反而是越学越迷糊啊,不知道有什么好的方法。越学越回到原点,最基本的都模糊了。

解决方案 »

  1.   

    第一:那回调方法CallBack是否理论也在线程2上被调用,就是线程2执行完Method方法后就执行回调方法CallBack,还是CallBack可能在另外的线程上被调用?(我程序跑下来的显示结果是:在同一线程上运行)
    是的,在另一个线程上执行的。第二:如果回调方法CallBack在线程2上被调用,那为什么CallBack抛出异常,线程1无法catch到,而且程序直接就崩溃了?
    因为异常机制是本线程有效的。另外线程的异常需要单独注册System.Windows.Forms.Application.ThreadException事件第三:如果回调方法CallBack不在线程2上被调用,而是在另外的新线程上调用,抛错了,那我怎么处理?能把异常抛给线程1吗?
    忽略此问题第四:为什么在如上代码中,即使Method方法抛错,回调函数依然执行?
    这个不知道。本机没装源码。不知道.net如何实现这个的。
      

  2.   

    大哥,又是你,呵呵,看来只有你能救我了。谢谢啊。
    针对第一个问题,你的回答我还是有点疑惑,为什么要在另外的线程上运行呢?我怎么能用代码证明?因为我跑来跑去结果都是在同一个线程上。而且我自己想象,回调方法为什么要在另外的线程上执行呢?回调就是在异步方法执行后就需要调用的函数,干嘛在另外的新线程上调用?虽然BeginInvoke是用线程池,比单纯新建线程要快速,但是何必要把那个线程扔回线程池,然后再取一个?(这里我又引申想问另外一个问题,难道用线程池就不要线程上下文切换了吗?)
    第二个问题,Application.ThreadException没用过,去看下,呵呵,不懂再问大哥你,呵呵。但从名字上看怎么感觉是Windos Form的东西啊?在控制台应用程序上也能用吗?
      

  3.   

    begininvoke调用后,要有一个endinvoke,endinvoke可以捕捉异常
      

  4.   

    Delegate.Invoke
    Delegate.Invoke用于再当前线程上执行一个委托。我们知道委托是一个函数或方法的引用,Delegate.Invoke就是调用方法或函数的机制。
    Delegate.BeginInvoke
    Delegate.BeginInvoke用来异步执行一个委托,在一个单独的线程中执行,所以不会阻塞当前的线程。在调用Delegate.BiginInvoke后,需要在某个时刻调用EndInvoke以避免资源泄露。由于委托方法是在单独的线程中,所以不能更新UI线程的属性或者调用任何潜在更新UI的方法。比方说,如果想要更新一个进度条,填充一个列表或其他类似的工作,必须使用一个不同的机制:Control.Invoke或Control.BeginInvoke
    begininvoke是在一个单独的线程中执行的不同于invoke
      

  5.   

    所以static void Method()和static void CallBack(IAsyncResult ir)都在另一个线程上
      

  6.   

    谢谢,当然我可以在回调方法的线程上调用EndInvoke,然后处理掉异常,只能是处理掉,但是这样我的主线程,在实际情况中可能就是我的主应用程序,就没法知道程序出过错了,至少是不能及时知道,我得记个Log什么的啊,后期自己去看了。就是这个问题比较痛苦。还有就是为什么异步方法出错,回调依然执行?
    谢谢各位了!
      

  7.   

    大哥,我看了下Programming .NET Components这本书,在第七章关于回调方法,有这么一段话,.NET uses a thread from the thread pool to execute the method dispatched via BeginInvoke( ). When the asynchronous method execution is completed, instead of quietly returning to the pool, the worker thread calls the callback method.
    那不是说,回调方法和异步方法是在同一个线程执行的吗?我现在迷糊了。
      

  8.   

    意思是BeginInvoke启动了一个线程,EndInvoke和BeginInvoke创建的线程在同一个线程。我说的另外一个线程是相对UI主线程的另外一个。
      

  9.   

    书上说的同一个是说begininvoke和endinvoke在同一个线程。
      

  10.   

    貌似不是吧?找了这书的中文版,也是说回调方法和异步方法在一线程上执行,而且我EndInvoke可以在异步方法或者回调方法中执行啊?不是很明白老大你的意思。
    还有关于昨天怎么让线程1知道线程2,“因为异常机制是本线程有效的。另外线程的异常需要单独注册System.Windows.Forms.Application.ThreadException事件”这个对我启发比较大,呵呵,我发现自己注册个事件也可以的,可以通过事件通知,谢谢大哥啊!