我尝试使用Thread.Sleep()
进行试验。我用一个按钮创建了基本的Windows窗体应用程序。
private void button1_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(DoStuff);
thread1.Start();
for (int i = 0; i < 100000; i++)
{
Thread.Sleep(500);
button1.Text +=".";
}
}
public void DoStuff()
{
//DoStuff
}
当我单击我的按钮时,DoStuff
方法工作正常,但GUI冻结并且没有任何反应。有人能解释我为什么吗?
答案 0 :(得分:6)
Thread.Sleep
只是睡眠当前线程(即阻止它做任何事情,例如重绘,处理点击等),在你的情况下是UI线程。如果您将Sleep
放在DoStuff
中,那么即使您无法更新button1,也不会遇到单独的线程。根据您使用的.NET版本,考虑使用任务并行库,如下所示:
private TaskScheduler _uiScheduler;
public Form1()
{
InitializeComponent();
_uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
}
private void button1_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(DoStuff);
thread1.Start();
// Create a task on a new thread.
Task.Factory.StartNew(() =>
{
for (int i = 0; i < 100000; i++)
{
Thread.Sleep(500);
// Create a new task on the UI thread to update the button
Task.Factory.StartNew(() =>
{ button1.Text += "."; }, CancellationToken.None, TaskCreationOptions.None, _uiScheduler);
}
});
}
答案 1 :(得分:3)
要使UI保持活动状态,您需要主UI线程为其消息泵提供服务。它只能在不处理UI事件时执行此操作。在你的情况下功能
private void button1_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(DoStuff);
thread1.Start();
for (int i = 0; i < 100000; i++)
{
Thread.Sleep(500);
button1.Text +=".";
}
}
大约100000*500
毫秒不会返回。在执行此事件处理程序时,UI线程正忙。它正在执行此事件处理程序。因此,它无法维护消息泵。因此,您的应用程序的UI冻结。
答案 2 :(得分:0)
为此,您最好使用Timer
,但如果您希望当前的代码有效,则需要在更新Application.DoEvents();
后添加button.Label += "."
答案 3 :(得分:0)
如果您是多线程新手,我强烈建议您查看任务并行库(TPL)。它简化了线程,并为您提供工具来帮助保证UI线程上发生回调(延续)线程。
TPL位于System.Threading.Tasks命名空间中。
更新:刚看到你对.Net v2的评论。 TPL是在.NET v3.5中引入的,也可能是在v4中引入的。
答案 4 :(得分:0)
所有上述方法都有效,但我建议只使用async void
Sleep()
只暂停当前线程int
毫秒,如果整个程序运行1个线程,它将暂停整个程序。不要引用我这个,我相信async会专门为该函数创建一个新线程。
下面我提到了一个更好的睡眠功能。
要调用函数asleep(milliseconds)
,
将“毫秒”替换为您希望睡眠的毫秒数。
功能代码:
public async void asleep(int time){
await Task.Delay(time)
}
答案 5 :(得分:-1)
重新安排代码如下
private void button1_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(DoStuff);
thread1.Start();
}
public void DoStuff()
{
for (int i = 0; i < 100000; i++)
{
Thread.Sleep(500);
//Invoke goes here
}
}
现在您在一个单独的线程中运行您的WORK并释放您的UI线程以进行常规工作(绘图相关或其他工作)
注意 - 现在您需要调用方法来更改按钮文本,否则您将收到警告&#34;跨线程操作无效&#34;
有关Invokes的更多信息 - How to update the GUI from another thread in C#?