为什么使用多个线程?
已经有许多单线程的客户端应用程序,而且每天还有许多正在被写。在许多情况下,单线程的行为已经足够了。
然而,在某些特定的应用程序中加入一些异步行为可以提高你的经验。典型的数据库前端程序是一个很好的例子。
数据库查询需要花费大量时间完成。在一个单线程的应用程序里,这些查询会导致window消息处理能力阻塞,导致程序的用户交互被冻结。解决办法就是,这个我将要详细描述,用一个线程处理来自操作系统的消息,而另外一个线程做一个很长的工作。在你的代码中使用第二个线程的重要原因就是即使在幕后有一个繁忙的工作在进行,也要保证你的程序的用户交互有响应。
我们首先看一下执行一长串操作的单线程的GUI程序。然后我们将用额外的线程整理该程序。
Figure 1 是用C#写的一个程序的完整源代码。它创建了一个带有文本框和按钮的窗体。如果你在文本框中键入了一个数字,然后按下按钮,这个程序将处理你输入的那个数字,它表示秒数,每秒钟响铃一次代表后台的处理。除了Figure 1 的代码外,你可以从本文开头的链接中下载完整的代码。下载或键入Figure 1 所示的代码,在读之前编译运行它,(编译前,在Visual Studio.NET中右击你的工程,加入Microsoft Visual Basic运行时引用)当你试着运行Figure 1 中的
SingleThreadedForm.cs应用程序时,你马上就会看到几个问题。
Figure 1 SingleThreadedForm.cs
using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using Microsoft.VisualBasic;
class App {
// Application entry point
public static void Main() {
// Run a Windows Forms message loop
Application.Run(new SingleThreadedForm());
}
}
// A Form-derived type
class SingleThreadedForm : Form {
// Constructor method
public SingleThreadedForm() {
// Create a text box
text.Location = new Point(10, 10);
text.Size = new Size(50, 20);
Controls.Add(text);
// Create a button
button.Text = "Beep";
button.Size = new Size(50, 20);
button.Location = new Point(80, 10);
// Register Click event handler
button.Click += new EventHandler(OnClick);
Controls.Add(button);
}
// Method called by the button's Click event
void OnClick(Object sender, EventArgs args) {
// Get an int from a string
Int32 count = 0;
try { count = Int32.Parse(text.Text); } catch (FormatException) {}
// Count to that number
Count(count);
}
// Method beeps once per second
void Count(Int32 seconds) {
for (Int32 index = 0; index < seconds; index++) {
Interaction.Beep();
Thread.Sleep(1000);
}
}
// Some private fields by which to reference controls
Button button = new Button();
TextBox text = new TextBox();
}
在你第一次测试运行时,在文本框中输入20,按下按钮。你将看到程序的用户交互变得完全没有响应了。你不能单击按钮或者编辑文本框,程序也不能被从容的关闭,如果你覆盖该窗体接着会显示一个窗口的部分区域,它将不再重绘自己(见 Figure 2),这个程序被锁定足足20秒, 然而它还可以继续响铃,证明它还没有真正的死掉。这个简单的程序解释了单线程GUI程序的问题。
我将用多线程解决第一个问题:未响应的用户交互,但首先我将解释是什么导致了这种现象。