c#在主线程上使用thread.join时从子线程更新标签

时间:2017-07-17 04:09:35

标签: c# multithreading blocking

我一直试图做一些看似应该比我做的更容易的事情。

我想从一些工作线程更新程序GUI上的状态标签(I.E.进度)。

我无法使用同步调用调用,因为主线程在thread.Join()上被阻塞;重新启用接口输入/清理线程。这会导致程序冻结。

我不想使用异步的BeginInvoke因为它等到程序完成后才更新进度...失败的目的。

tl; dr - 我知道为什么它不起作用,但我不确定如何解决它。

Button_Search_Click(object sender, EventArgs e)()
{
    DisableInput(); //Block input on start of function
    Cursor.Current = Cursors.WaitCursor; //set wait cursor

    //read combobox input
    string objectType = comboBox_Object.SelectedItem.ToString();
    string conditionType = comboBox_ConditionType.SelectedItem.ToString();
    string conditionOperator = comboBox_equals.SelectedItem.ToString();

    //create a list of worker threads
    List<Thread> workerThreads = new List<Thread>();

    //for each line in the textbox
    foreach (string searchText in textBox_SearchText.Lines)
    {
        if (String.IsNullOrWhiteSpace(searchText)) continue;

         //foreach line in a listbox
        foreach (String uri in Get_selected_sites())
        {
            string cred = (creddict[uri]);

            Thread thread = new Thread(() => Search(uri, cred, objectType, conditionType, conditionOperator, searchText));
            workerThreads.Add(thread);
            thread.Start(); //start main "work" function
        }

        // Wait for all the threads to finish
        foreach (Thread thread in workerThreads)
        {
            thread.Join();
        }
    }

    Displaydata();
    EnableInput(); //unlock input
    Cursor.Current = Cursors.Default; //set normal cursor
}

Search(uri, cred, objectType, conditionType, conditionOperator, searchText)
{
DoStuff();

//Update toolStripStatusLabel with progress stored in global int variable

//This doesn't work well because it waits until Thread.join() to update status label.
//BeginInvoke(new Action(() => Results_Count.Text = "Total Results = " + totalResults)); 

//This doesn't work at all because the main thread is blocked on Thread.Join()  -- it freezes the program
//statusStrip1.Invoke(new Action(() => Results_Count.Text = "Total Results = " + totalResults)); 

//This doesn't work/errors/crashes because the GUI is being modified by a thread other than main
//Results_Count.Text = "Total Results = " + totalResults;

DoMoreStuff();
}

非常感谢您提供的任何提示!

1 个答案:

答案 0 :(得分:0)

修复你的方法,看起来更像是这样:

async void Button_Search_Click(object sender, EventArgs e)()
{
    DisableInput(); //Block input on start of function
    Cursor.Current = Cursors.WaitCursor; //set wait cursor

    //read combobox input
    string objectType = comboBox_Object.SelectedItem.ToString();
    string conditionType = comboBox_ConditionType.SelectedItem.ToString();
    string conditionOperator = comboBox_equals.SelectedItem.ToString();

    //create a list of worker threads
    List<Task> workerTasks = new List<Task>();

    //for each line in the textbox
    foreach (string searchText in textBox_SearchText.Lines)
    {
        if (String.IsNullOrWhiteSpace(searchText)) continue;

         //foreach line in a listbox
        foreach (String uri in Get_selected_sites())
        {
            string cred = (creddict[uri]);

            workerTasks.Add(Task.Run(() => Search(uri, cred, objectType, conditionType, conditionOperator, searchText)));
        }

        await Task.WhenAll(workerTasks);
    }

    Displaydata();
    EnableInput(); //unlock input
    Cursor.Current = Cursors.Default; //set normal cursor
}

这样,Button_Search_Click()在任务运行时不会阻止UI线程,您可以使用普通Invoke()或任何您喜欢的机制将更新发布到UI线程。