C# WinForm TPL 任务调用意外结果-我在这里做错了啥? [复制]

Posted

技术标签:

【中文标题】C# WinForm TPL 任务调用意外结果-我在这里做错了啥? [复制]【英文标题】:C# WinForm TPL Task call unexpected result- what did I do wrong here? [duplicate]C# WinForm TPL 任务调用意外结果-我在这里做错了什么? [复制] 【发布时间】:2021-07-13 17:09:01 【问题描述】:

您好,我是多线程和 TPL 的新手 - 测试任务调用并将状态写回主 UI 上的文本框,但没有得到预期的结果。我正在测试此功能,因为我需要为我的工作实现该工具。我的程序将循环创建 30 个任务并启动并在文本框中显示正在处理的任务。我将“i”计数器传递给 DoWork 函数并显示该“i”计数器。我的代码如下

private void DoWork(object state)
       
           object[] obj = state as object[];
           int i = Convert.ToInt32(obj[0]);

           
           Invoke(new MethodInvoker(delegate()
           

               richTextBox1.Text += "Testing" + i.ToString() + "\n";

           ));
       

       private void btnTest_Click(object sender, EventArgs e)
       
           for (int i = 0; i < 30; i++)
           
               Task t1 = new Task(() => DoWork(new object[] i) );            
               t1.Start();

           
       

我希望在文本框中以随机顺序显示 1 到 30,但它会像这样显示。我已附上图像并在此处显示。 enter image description here

结果看起来很奇怪,主要显示如下(几乎所有显示 30)。 “i”是作为对象传递给“DoWork”的参数。

测试0 测试3 测试12 测试30 测试30 测试30 测试30 测试30 测试30 测试30 测试30 测试30 测试30 测试30 测试30 测试30 测试30 测试30 测试30 测试30 测试30 测试30 测试30 测试30 测试30 测试30 测试30 测试30 测试30 测试30

非常感谢您帮助我理解并解决此问题。

问候 威廉

【问题讨论】:

private void btnTest_Click... 更改为private async void btnTest_Click...。然后将Task t1 = new Task(() =&gt; DoWork(new object[] i) ); 更改为await Task.Run(() =&gt; DoWork(new object[] i) ); 。你真的应该 read up on 基础 asnyc/await 编程。 谢谢@Andy。我会读完的 您可能应该使用BeginInvokeInvokeAsync,因为Invoke 会导致GUI 线程死锁。 【参考方案1】:

主要问题可能是您使用了changing variable in your delegate。

将代码改为

var tmp = i;
Task t1 = new Task(() => DoWork(new object[]  tmp ) );   

我还建议您简单地编写代码,即

private void DoWork(int i)

var tmp = i;
Task.Run(() => DoWork(tmp));

请注意,我不确定您希望此示例演示什么。您实际上是在线程池上调度一堆任务,而这些任务唯一要做的就是将新任务调度回主线程。虽然输出可能有些随意,但它可能具有较低的随机性。

另一个好的做法是始终处理任务的结果。如果您只是开始一项任务,您将无法知道它是否因异常而失败,这可能会隐藏您程序中的错误。

【讨论】:

谢谢。这个帮助。 :)

以上是关于C# WinForm TPL 任务调用意外结果-我在这里做错了啥? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

C# 解决调用winform窗体顶置且解决任务栏图片显示问题

是否可以在 C# 2.0 中使用任务并行库 (TPL)?

使用任务并行库 (TPL) 进行轮询

C# 实现Winform全屏后不遮挡任务栏,显示任务栏

意外行为 - TPL DataFlow BatchBlock 在 TriggerBatch 执行时拒绝项目

C#异步调用,界面假死