使用Parallel.Invoke时“用户代码未处理的异常”

时间:2013-09-12 12:15:04

标签: c# c#-4.0 task-parallel-library

我在这里遇到了例外:

  

MyException未被用户代码

处理

事实上我已经尝试了这个,但是

问题是什么以及如何解决?我想要实现的是获取异常是由try catch包围parallel.All。现在,它不知道try catch,并提示我异常未被用户代码处理。注意到我需要TestParallel1方法抛出异常,因为这是我所拥有的程序的简化格式。鉴于异常,我希望立即停止所有其他线程。此外,我希望异常传播到并行之外。

namespace WindowsFormsApplication1
{
    static class Program
    {

        public static void Main()
        {
            try
            {
                List<Action> act = new List<Action>
                      {
                         ()=>TestParallel1(),
                         () => TestParallel1()
                      };

                Parallel.Invoke(act.ToArray());
            }
            catch (AggregateException ae)
            {
                foreach (var e in ae.InnerExceptions)  // note the 's' in InnerExceptions
                {
                    //do something with 'e'
                }
                //do something
            }
        }

        public class MyException : Exception
        {
        }

        public static void TestParallel1()
        {
            throw new MyException();
        }
    }
}

enter image description here

3 个答案:

答案 0 :(得分:2)

您在调试器中收到“未处理的用户代码”,因为您已启用“仅我的代码”设置(并且原始异常在技术上不是由您的代码处理,而是而是由框架的代码处理)。

关闭“只是我的代码”,您将获得不同的体验。

注意,这只是调试经验 - 它对常规程序流没有任何影响。

请参阅:http://msdn.microsoft.com/en-us/library/h5e30exc(v=vs.90).aspx

答案 1 :(得分:1)

并行成员将始终抛出聚合异常。你抓错了类型。

您需要的更改:

//catch(MyException e)
catch (AggregateException ae)
{       

   foreach (var e in ae.InnerExceptions)  // note the 's' in InnerExceptions
   {
        //do something with 'e'
   }
}

答案 2 :(得分:0)

要捕获此异常并仍然使用Parallel,您可以执行此操作:

        List<Action> act = new List<Action> { () => TestParallel1(), 
                                              () => TestParallel1() };

        Parallel.ForEach(act, a =>{
            try
            {
                a.Invoke();
            }
            catch (MyException ae)
            {
                //do something
            }
        });

修改

如果事件和代表对你好,那么这样的事情可能会成功 我知道这段代码可能看起来更好但它会告诉你这个想法,所以我希望它会对你有所帮助:)。

public partial class MainWindow : Window
{
    List<MyThread> threads = new List<MyThread>();

    public MainWindow()
    {
        var thread1 = new MyThread();
        thread1.A = () => TestParallel1();
        thread1.RaisError += RaisError;

        var thread2 = new MyThread();
        thread2.A = () => TestParallel1();


        threads.Add(thread1);
        threads.Add(thread2);

        Parallel.ForEach(threads, t => { t.Start(); });
    }

    public void RaisError()
    {
        Parallel.ForEach(threads, t => { t.Stop(); });
    }

    public static void TestParallel1()
    {
        throw new MyException();
    }
}

public class MyException:Exception{}


public class MyThread
{
    public Action A { get; set; }
    public delegate void Raiser();
    public event Raiser RaisError;

    public void Start()
    {
        try
        {
            A.Invoke();
        }
        catch (MyException me)
        {
            RaisError();
        }
    }

    public void Stop()
    {
        // do some stop
    }
}

编辑2

您也可以这样做,但您应该首先阅读This Answer(来自Scott Chamberlain)

        List<Action> act = new List<Action> { () => TestParallel1(), 
                                          () => TestParallel1() };

        Parallel.ForEach(act, (a, state) =>
        {
            try
            {
                a.Invoke();
            }
            catch (MyException ae)
            {
                state.Stop();
            }
        });