l versC#多线程问题
Posted
技术标签:
【中文标题】l versC#多线程问题【英文标题】:l versC# multithread issue 【发布时间】:2018-04-13 16:57:35 【问题描述】:文件复制线程正在运行时,我无法让 ui 线程更新 ui。我的最终目标是让动画继续旋转,直到大文件复制最终完成,让用户知道程序没有冻结。这是一个非常简单的服务器到服务器文件复制程序。
谁能告诉我我做错了什么?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO;
using System.Threading.Tasks;
namespace WindowsFormsApplication1
public partial class Form1 : Form
public Form1()
InitializeComponent();
private void ResetProgress()
lblStep1.Image = null;
private void SetupProgress()
lblStep1.Image = global::animation1.Properties.Resources.animation;
private void fileCopy()
File.Copy("large file source", "large file destination", true);
private void Form1_Load(object sender, EventArgs e)
lblStep1.Image = global::animation1.Properties.Resources.animation;
private async void button1_Click(object sender, EventArgs e)
SetupProgress();
await Task.Run(() => fileCopy());
ResetProgress();
private void btnStop_Click(object sender, EventArgs e)
// unhandled currently
* 原始版本 *
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO;
using System.Threading.Tasks;
namespace WindowsFormsApplication1
public partial class Form1 : Form
private Thread workItemsProducerThread;
private Thread workItemsCopyThread;
public Form1()
InitializeComponent();
private void ResetProgress()
lblStep1.Image = null;
private void SetupProgress()
this.BeginInvoke((MethodInvoker)delegate ()
lblStep1.Image = global::animation1.Properties.Resources.animation;
);
private void fileCopy()
File.Copy("Large file source", "Large file destination", true);
this.BeginInvoke((MethodInvoker)delegate ()
MessageBox.Show("Done");
);
private void Form1_Load(object sender, EventArgs e)
lblStep1.Image = global::animation1.Properties.Resources.animation;
private void btnStart_Click(object sender, EventArgs e)
this.workItemsProducerThread = new Thread(new ThreadStart(this.SetupProgress));
this.workItemsProducerThread.IsBackground = true;
this.workItemsProducerThread.Start();
this.SetupProgress();
this.workItemsCopyThread = new Thread(new ThreadStart(this.fileCopy));
this.workItemsCopyThread.IsBackground = true;
this.workItemsCopyThread.Start();
while (workItemsCopyThread.IsAlive)
Thread.Sleep(1000); // wait
MessageBox.Show("Done");
private void btnStop_Click(object sender, EventArgs e)
if (this.workItemsProducerThread != null)
this.workItemsProducerThread.Abort();
lblStep1.Image = global::animation1.Properties.Resources.animation;
private void btnTest_Click(object sender, EventArgs e)
fileCopy();
【问题讨论】:
相反,没有理由在另一个线程上运行 SetupProgress。这是个坏主意。 好的,我已经尝试了这两个建议,但症状仍然相同。我已经尝试从主 UI 运行 SetupProgress 并将 begininvoke 替换为仅调用,但行为没有改变。 @Jay 那是因为代码太复杂了。您不需要线程、调用或中止。 Henk Holterman 的回答显示了使用内置的 Task.Run 和 async/await 编写它是多么容易。 Panagiotis,你介意试试我的例子看看它是否适合你吗?fileCopy
应该是async
方法,并从Task
移出,你不需要这里的线程池——它是IO 方法,它们正是为async
设计的。
【参考方案1】:
不要在点击处理程序中睡觉。这会冻结 UI 线程。只需让时钟处理程序退出即可。在您的文件复制线程中,当副本不是时。使用 Invoke(或 BeginInvoke)使完成的消息框在 UI 线程上弹出。
【讨论】:
如果我理解正确,我已经进行了上述更正,但仍然遇到相同的症状? 当 Task.Run 和async/await
可用时,没有理由使用 Invoke 或线程
您需要从点击处理程序中删除:while isalive 循环和消息框。 (顺便说一句,异步更容易)【参考方案2】:
试试这种老式风格
private void SetupProgress()
Invoke((MethodInvoker) delegate
lblStep1.Image = global::animation1.Properties.Resources.animation;
);
private Thread TDoSomeWork()
var t = new Thread(() => DoSomeWork());
t.Start();
return t;
TDoSomeWork();
【讨论】:
以上是关于l versC#多线程问题的主要内容,如果未能解决你的问题,请参考以下文章