Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 这是在Windows窗体应用程序中更新UI线程的安全方法吗?_C#_Multithreading - Fatal编程技术网

C# 这是在Windows窗体应用程序中更新UI线程的安全方法吗?

C# 这是在Windows窗体应用程序中更新UI线程的安全方法吗?,c#,multithreading,C#,Multithreading,我不太熟悉多线程,我想知道这是否是从其他线程更新UI线程的最安全的方法。我的代码的工作流程如下: // this is the button click action private async void button_Click(object sender, EventArgs e) { //do some things to local variables await create(); } // this task creates the thing and does

我不太熟悉多线程,我想知道这是否是从其他线程更新UI线程的最安全的方法。我的代码的工作流程如下:

// this is the button click action
private async void button_Click(object sender, EventArgs e)
{
    //do some things to local variables

    await create();
}

// this task creates the thing and does all the heavy processing
public Task create()
{
    return Task.Run(() => 
    {
        try
        { 
            //some code

            consoleOut(string);
        }
        catch (Exception e)
        {
            //do things
        }
    }
}

// custom logging that prints formatted stuff out to a ListBox
public void consoleOut(String str)
{
    if (this.InvokeRequired)
    {
        this.Invoke(
            new MethodInvoker(
            delegate() { consoleOut(str); }));
    }
    else
    {
        //print stuff
        ListBox.Items.Add(str);
    }
}
这是从
create
Task更新我的列表框内容的最安全方法吗

作为参考,我结合了前面这些问题中的内容,但没有对代码的作用进行太多解释,因此我提出了关于线程安全的问题,以及是否有更好的方法:


这就是我使用多线程的方式,它对我来说100%都很好。。。虽然有人可能会说这是有史以来最糟糕的

//start a second thread with parameters in this case
Thread filterThd = new Thread(() => filterLike(FilterTextBox.Text.ToLower(),column));
                filterThd.Start();

//somewhere in your thread, it updates the ui like this
Form2 f2= (Form2)System.Windows.Forms.Application.OpenForms["Form2"];
        f2.Invoke((MethodInvoker)(() => f2.DataGrid.DataSource = null));

IMHO,你采取的方法有两个问题:

  • 你把事情搞得太复杂了-以后再谈
  • 根据
    //some code
    部分所做的工作,您可能最终会得到一个冻结的应用程序
  • 现在,让我们把每一部分都撕成碎片

    过于复杂的原因是,虽然基于
    任务
    的方法是不完整的,但您混合了两种不同的方法来做基本相同的事情,即
    调用
    方法和
    任务

    然而,最大的问题是
    //某些代码的部分;如前所述,如果该部分占用大量资源(即运行时间较长),则最终可能会导致应用程序冻结,因为运行该方法的线程是UI线程,该线程使用分配给应用程序的UI资源来处理消息和绘制控件

    我将代码分为两个逻辑部分:

    • 处理和处理数据的人
    • 另一个将字符串记录到UI的
    代码应该如下所示:

    private async void button_Click(object sender, EventArgs e)
    {
        //do some things to local variables
        await Task.Run(() => 
        {
            // some code
        })
        .ContinueWith(p => ListBox.Items.Add(str),
             TaskScheduler.FromCurrentSynchronizationContext());
    }
    

    除了消除混乱之外,上面的代码将工作分为两个任务,这两个任务可以按不同的时间安排:第一个任务可以在后台线程上执行,并且不会影响UI,而继续将在UI线程上运行,这是由于通过允许您安全访问控件而传递的限制,即使它是安全的在UI线程上执行它的执行时间非常短,因此应用程序不会冻结。

    Async/await是。您之所以调用多线程,是因为您显式地使用了
    Task.Run()
    ,但我怀疑您是否应该这样做。那么在这种情况下,除了
    Task.Run()
    ,还有什么替代方案呢?我之所以这样写是因为它被编译:)保持
    按钮的原样,使
    创建
    异步
    ,删除
    返回任务。运行(()=>{}
    ,将实际代码放在那里(应该包括对
    等待的
    其他
    异步
    方法的调用),然后是
    ListBox.Items.Add(str)。完全删除
    consoleOut
    。嗯,这是有道理的,但是
    consoleOut
    在程序中被调用多次,并从
    create
    以外的方法调用。完全删除它将导致程序中出现大量重复代码。我只放了
    ListBox.Items.Add(str)在OP中为简洁起见,它做的不仅仅是时间戳、格式设置等,它也是一种重载方法,然后保留
    控制台输出
    ,但从中删除调用代码,只保留实际的
    .Add()
    等。谢谢。所以有两件事:1)
    //一些代码确实是处理密集型的,会完全冻结/延迟gui(这导致了混乱)。2) 我认为我不能像那样硬编码
    ListBox.Add(str)
    ,因为我原来的
    ConsoleOut
    都是重载的,可以以相同的方式打印各种数据类型,并且在整个
    //某些代码中多次调用