winforms 如何在C#中创建一对一的多线程关系和异常处理

a6b3iqyw  于 12个月前  发布在  C#
关注(0)|答案(1)|浏览(128)

这是我第一次在多线程应用程序上工作(一般来说,不仅仅是用C#),因此我只知道关于它的简单概念。我基本上实现了System.Threading命名空间。
我有一个字典,它将对象A与它的ID(Dictionary<int,A>)联系起来。每个A都要做一个操作(每个A都有相同的操作),我希望这个操作在一个单独的线程列表中工作,每个A一个。
我知道System.Threading是实现多线程的糟糕方法,但我现在只知道一点这个命名空间。我做了一些东西:

public class ThreadManager
{
    private Dictionary<int, A> _aList;
    public Dictionary<int, A> AList
    {
        get { return _aList; }
        set { _aList = value; }
    }

    private Dictionary<int, Thread> _threadList;
    public Dictionary<int, Thread> ThreadList
    {
        get { return _threadList; }
        set { _threadList = value; }
    }

    public ThreadManager(Dictionary<int, A> list)
    {
        AList = list;
        ThreadList = new Dictionary<int, Thread>();

        foreach (A a in AList)
        {
            int id = a.Id;
            ThreadList.Add(id, new Thread(new ParameterizedThreadStart(Operation)));
        }
    }

    public void Operation(object data)
    {
        try
        {
            /*** do something***/
        }
        catch (Exception e)
        {
            /*** throw exception ***/
        }
    }
}

字符串
当我运行特定的线程在我的应用程序代码点:

ThreadManager.ThreadList[i].Start(data)


做需要的操作似乎工作得很好。但是,我认为这个解决方案真的很丑,功能也不是很好。
此外,还有一个大问题。当异常在throw中时,正如预期的那样,它不是catch out of thread。我可以在代码的另一个点捕获线程异常吗?它工作在不同的线程上(例如主线程)。

编辑:

为了明确,我想没有线程阻塞主线程。我需要能够在主线程上操作,而操作工作。

hgc7kmma

hgc7kmma1#

我的建议是使用Task.RunParallel.ForEach的组合:

private async void button1_Click(object sender, EventArgs e)
{
    try
    {
        Cursor = Cursors.WaitCursor;
        button1.Enabled = false;

        await Task.Run(() =>
        {
            ParallelOptions options = new()
            {
                MaxDegreeOfParallelism = Environment.ProcessorCount
            };

            Parallel.ForEach(dictionary, options, entry =>
            {
                var (key, value) = entry;
                /* do something with the key and value */
            });
        });
    }
    catch (AggregateException aex)
    {
        /* handle aex.InnerExceptions (can be more than one) */
    }
    finally
    {
        button1.Enabled = true;
        Cursor = Cursors.Default;
    }
}

字符串
1.使用asyncawait关键字允许您编写不阻塞UI线程的异步代码,与编写正常同步代码的方式相同。当异步操作正在进行时,UI保持响应。

  1. Task.Runaction委托的处理卸载到ThreadPool线程。ThreadPool是由.NET基础结构管理的可重用线程池。如果需要,您可以使用ThreadPool.SetMinThreads方法对其进行微调。
  2. Parallel.ForEach在多个ThreadPool线程上并行调用body委托,强制执行MaxDegreeOfParallelism策略。如果您想要无限并行,请使用MaxDegreeOfParallelism = -1配置它。
    在异常的情况下,Parallel.ForEach将停止调用body委托,并将在所有当前运行的调用完成时完成。所有错误调用的错误将被捆绑在AggregateException中。此异常将首先由Task.Run传播,然后由await操作符传播,您可以在UI线程上使用Click事件处理程序中的try/catch块来处理它。(省略catch块),在这种情况下,它将被处理为通用的Application.ThreadException事件处理程序。如果你也省略了这个,WinForms应用程序默认显示的默认错误弹出窗口将通知用户,并为用户提供继续或退出应用程序的选项。

相关问题