C# 这是在Windows窗体应用程序中更新UI线程的安全方法吗?
我不太熟悉多线程,我想知道这是否是从其他线程更新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
// 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
都是重载的,可以以相同的方式打印各种数据类型,并且在整个//某些代码中多次调用