【问题标题】:Multithreading on Windows Forms Unresponse Main FormWindows 窗体上的多线程无响应主窗体
【发布时间】:2018-04-02 21:19:00
【问题描述】:

我正在尝试将列表框中的 5 个随机整数数组按升序排序。在创建新线程并单独调用它时,当我选择“排序”按钮时,表单变得无响应。

public partial class Form1 : Form
{
    const int iSize = 5;
    int[] iArray = new int[iSize];
    Random rnd = new Random();

    public Form1()
    {
        InitializeComponent();
    }

    Thread th;

    private void btnGenerate_Click(object sender, EventArgs e)
    {
        for (int i = 0; i < iArray.Length; i++)
        {
            iArray[i] = rnd.Next(0, 5);
            lbxNumbers.Items.Add(iArray[i]);
        }
    }

    public void threadMethod()
    {
        bubbleSort(iArray);
        foreach(int item in iArray)
        {
            lbxNumbers.Items.Add(item);
        }

    }

    private void btnSort_Click(object sender, EventArgs e)
    {
        th = new Thread(threadMethod);
        lblStatusUpdate.Text = "Sorting...";

    }

    private void btnClear_Click(object sender, EventArgs e)
    {
        lbxNumbers.Items.Clear();
    }

    public static void bubbleSort(int [] iArray)
    {
        bool isSorted = false;
        int lastUnsorted = iArray.Length - 1;
        while(!isSorted)
        {
            for(int i = 0; i < iArray.Length-1; i++)
            {
                if(iArray[i] > iArray[i+1])
                {
                    swap(iArray, i, i + 1);
                    isSorted = false;

                }

            }
        }
    }
    public static void swap(int [] iArray, int i, int j)
    {
        int tmp = iArray[i];
        iArray[i] = iArray[j];
        iArray[j] = tmp;
    }

}

我不确定线程​​实际上在哪里启动。列表框可以立即生成数组并将其清除,但排序使其冻结。我也不确定是否需要在此表单上使用后台工作人员工具。

【问题讨论】:

  • 您创建了线程,但我没有看到您启动过它...无论哪种方式,您都遇到了跨线程问题。
  • 不要使用线程来更新 UI;使用async/await

标签: c# multithreading winforms


【解决方案1】:

阐述Dour High Arch's评论。

编辑

您的代码存在几个问题。 UI 更新只能在 UI 线程上完成。您可以使用 SychronizationContext 或 async/await 为您处理它。此外,您的冒泡排序缺少 while 循环的退出条件,因此它将永远运行。下面演示了使用 async/await 是如何工作的。

private async void btnSort_Click(object sender, EventArgs e)
{
    lblStatusUpdate.Text = @"Sorting...";
    await Run();

}


public async Task Run()
{
    //This line runs asynchronously and keeps the UI responsive.
    await bubbleSort(iArray);

    //The remaining code runs on the UI thread
    foreach (int item in iArray)
    {
        lbxNumbers.Items.Add(item);
    }
}


public async Task bubbleSort(int[] iArray)
{
    await Task.Run(() =>
    {
        bool isSorted = false;
        while (!isSorted)
        {
            isSorted = true; //You were missing this to break out of the loop.
            for (int i = 0; i < iArray.Length - 1; i++)
            {
                if (iArray[i] > iArray[i + 1])
                {
                    swap(iArray, i, i + 1);
                    isSorted = false;

                }

            }
        }

    });
}

【讨论】:

  • 在这种情况下使用 await 的全部意义在于允许它使用同步上下文 for 你来处理,特别是这样你就不必这样做了。如果您要手动完成所有这些操作(您不应该这样做),那么根本没有理由使用await。您的代码与您完全删除它的代码没有什么不同。
  • 感谢@Servy 的反馈。我调整了答案。
【解决方案2】:

您不能对UI 或另一个内的主线程采取行动。

这一行:

lbxNumbers.Items.Add(item);

从另一个线程调用可能会导致麻烦。 在 WindowsForms 中处理这种情况的正确方法是使用

Control.Invoke 方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-30
    • 2010-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多