多线程应用程序(C# 和 Visual Basic)

使用 Visual Basic 和 C# 可以编写同时执行多项任务的应用程序。 有潜力支持其他一些任务的任务能够在不同的线程上执行,这种进程被称为“多线程处理”或“自由线程处理”。

使用多线程处理的应用程序对用户输入的响应能力更强,因为大量占用处理器的任务在不同的线程上执行时,用户接口是活动的。 多线程处理在创建可缩放应用程序时也很有用,因为工作量增加时可以添加线程。

备注

Visual Studio 2010 和 .NET Framework 4 提供了新的运行时、新的类库类型以及新的诊断工具,从而增强了对并行编程的支持。有关更多信息,请参见.NET Framework 中的并行编程

使用 BackgroundWorker 组件

创建多线程处理应用程序的最可靠方法是使用 BackgroundWorker 组件。 此类管理一个专用于处理您指定的方法的单独线程。 有关示例,请参见演练:利用 BackgroundWorker 组件进行多线程处理(C# 和 Visual Basic)

若要在后台开始一项操作,请创建 BackgroundWorker,并侦听报告操作进度和在操作完成时发出信号的事件。 可以通过编程方式创建 BackgroundWorker 对象,也可以将它从**“工具箱”“组件”选项卡中拖到窗体上。 如果在“窗体设计器”中创建 BackgroundWorker,则它会出现在“组件栏”中,而且它的属性会显示在“属性”**窗口中。

为后台操作做好准备

若要为后台操作做好准备,请添加 DoWork 事件的事件处理程序。 在此事件处理程序中调用耗时的操作。

若要开始此操作,请调用 RunWorkerAsync。 若要收到进度更新的通知,请处理 ProgressChanged 事件。 若要在操作完成时收到通知,请处理 RunWorkerCompleted 事件。

处理 ProgressChangedRunWorkerCompleted 事件的方法可以访问应用程序的用户界面,原因是这两个事件是在调用了 RunWorkerAsync 方法的线程上引发的。 但是,DoWork 事件处理程序无法使用任何用户界面对象,因为它在后台线程上运行。

创建和使用线程

如果需要对应用程序的线程的行为进行更多的控制,则可以自己管理线程。 但请注意,编写正确的多线程应用程序可能很困难:应用程序可能会因为争用条件而停止响应或遇到瞬态错误。 有关更多信息,请参见线程安全组件

通过声明类型为 Thread 的变量,并调用为要对新线程执行的过程或方法提供名称的构造函数,从而创建一个新线程。 以下代码提供了一个示例。

Dim newThread As New System.Threading.Thread(AddressOf AMethod)
System.Threading.Thread newThread =
    new System.Threading.Thread(AMethod);

ck8bc5c6.collapse_all(zh-cn,VS.110).gif启动和停止线程

若要开始执行新线程,可使用 Start 方法,如以下代码所示。

newThread.Start()
newThread.Start();

若要停止执行线程,可使用 Abort 方法,如以下代码所示。

newThread.Abort()
newThread.Abort();

除启动和停止线程之外,还可以通过调用 SleepSuspend 方法暂停线程、使用 Resume 方法继续挂起的线程,以及使用 Abort 方法销毁线程

ck8bc5c6.collapse_all(zh-cn,VS.110).gif线程方法

下表显示了一些可用于控制单个线程的方法。

方法

操作

Start

使线程开始运行。

Sleep

使线程暂停指定的一段时间。

Suspend

在线程到达安全点时,使其暂停。

Abort

在线程到达安全点时,使其停止。

Resume

重新启动挂起的线程

Join

使当前线程一直等到另一线程完成。 在与超时值一起使用时,如果该线程在分配的时间内完成,此方法将返回 True。

ck8bc5c6.collapse_all(zh-cn,VS.110).gif安全点

这些方法大多数都一目了然,但安全点对您可能是个新概念。 安全点是指代码中公共语言运行时可以安全地执行自动“垃圾回收”的位置。垃圾回收是指释放不再使用的变量并回收内存的过程。 调用线程的 AbortSuspend 方法时,公共语言运行时将对代码进行分析,确定让线程停止运行的适当位置。

ck8bc5c6.collapse_all(zh-cn,VS.110).gif线程属性

线程也包含许多有用的属性,如下表所示:

属性

IsAlive

如果线程处于活动状态,则包含值 True。

IsBackground

获取或设置一个布尔值,该值表示一个线程是否是或是否应当是后台线程。 后台线程与前台线程类似,但后台线程不阻止进程停止。 一旦某个进程的所有前台线程都停止,公共语言运行时就会对仍处于活动状态的后台线程调用 Abort 方法,从而结束该进程。

Name

获取或设置线程的名称。 通常用于在调试时发现各个线程。

Priority

获取或设置操作系统用于确定线程调度优先顺序的值。

ApartmentState

获取或设置用于特定线程的线程模型。 线程模型在线程调用非托管代码时很重要。

ThreadState

包含描述线程状态的值。

线程优先级

每个线程都有一个优先级属性,用于确定其执行所占用的处理器时间片大小。 操作系统为高优先级线程分配较长的时间段,并为低优先级线程分配较短的时间段。 新创建的线程具有值 Normal,但您可以将 Priority 属性更改为 ThreadPriority 枚举中的任何值。

有关各种线程优先级的详细说明,请参见 ThreadPriority

前台和后台线程

前台线程的运行时间不限定,而后台线程则在最后一个前台线程停止时立即停止。 可以使用 IsBackground 属性确定或更改线程的后台状态。

多线程处理窗体和控件

虽然多线程处理最适于运行过程和类方法,它也可以用于窗体和控件。 使用时,请注意以下几点:

  • 只要有可能,便仅在用来创建它的线程上执行控件的各种方法。 如果必须从另一个线程中调用控件的方法,则必须使用 Invoke 来调用该方法。

  • 不要使用 SyncLock (Visual Basic) 或 lock (C#) 语句来锁定操作控件或窗体的线程。 由于控件和窗体的方法有时回调到调用过程,因此可能会因无意中创建了死锁而终止运行(死锁是指两个线程都等待对方释放锁定,从而导致应用程序暂停的情况)。

请参见

参考

线程同步(C# 和 Visual Basic)

Invoke

InvokeRequired

Thread

概念

多线程过程的参数和返回值(C# 和 Visual Basic)

其他资源

组件中的多线程处理

HOW TO: Create a Thread by Using Visual C#(如何:使用 Visual C# 创建线程)