前言:多线程编程是应用程序开发中一个非常重要的部分,这里总结一些常见的线程(Thread)解决方案。注意:这里仅涉及Thread的常见解决方案,CLR 4.0以后的Task这里不做描述。
创建多线程应用程序的非常常见的方式是使用 BackgroundWorker 组件。 可以通过编程方式创建 BackgroundWorker 对象,在WinForm中也可以将它从“工具箱”的“组件”选项卡中拖到窗体上。我们看一下它的事件:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MyLib.WinFormEx
{
public partial class BackgroundWorkerForm : Form
{
public BackgroundWorkerForm()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
// DoWork 事件调用要执行的后台操作
backgroundWorker1.DoWork += backgroundWorker1_DoWork;
// ProgressChanged 事件更新后台操作进度信息(WorkerReportsProgress属性要设为true)
backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
// RunWorkerCompleted 事件在后台操作完成时触发
backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
}
private void startAsyncButton_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy != true)
{
// 开始执行后台操作
backgroundWorker1.RunWorkerAsync();
}
}
private void cancelAsyncButton_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
// 请求取消后台操作
backgroundWorker1.CancelAsync();
}
}
// DoWork 事件调用要执行的后台操作;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
// 执行耗时的操作并报告进度
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}
// ProgressChanged 事件更新后台操作进度信息(WorkerReportsProgress属性要设为true);
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
resultLabel.Text = (e.ProgressPercentage.ToString() + "%");
}
// RunWorkerCompleted 事件在后台操作完成时触发;
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
resultLabel.Text = "Canceled!";
}
else if (e.Error != null)
{
resultLabel.Text = "Error: " + e.Error.Message;
}
else
{
resultLabel.Text = "Done!";
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MyLib.ConApp.ThreadTest
{
public class ThreadTimerProgram
{
public static void Main(string[] args)
{
// 创建事件以在计时器回调中信号超时计数阈值。
AutoResetEvent autoEvent = new AutoResetEvent(false);
StatusChecker statusChecker = new StatusChecker(10);
// 创建调用计时器方法的推断委托。
TimerCallback tcb = statusChecker.CheckStatus;
// 创建一个计时器, 它指示委托在一秒钟之后调用 CheckStatus, 此后每隔1/4 秒发出一次信号。
Console.WriteLine("{0} 创建计时器.\n", DateTime.Now.ToString("h:mm:ss.fff"));
Timer stateTimer = new Timer(tcb, autoEvent, 1000, 250);
// 当自动事件信号时, 将周期更改为每1/2 秒。
autoEvent.WaitOne(5000, false);
stateTimer.Change(0, 500);
Console.WriteLine("\n更改期间.\n");
// 当自动事件第二次发出信号时, 释放计时器。
autoEvent.WaitOne(5000, false);
stateTimer.Dispose();
Console.WriteLine("\n销毁计时器.");
}
}
class StatusChecker
{
private int invokeCount;
private int maxCount;
public StatusChecker(int count)
{
invokeCount = 0;
maxCount = count;
}
// 此方法由计时器委托调用。
public void CheckStatus(Object stateInfo)
{
AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
Console.WriteLine("{0} 正在检查状态 {1,2}.", DateTime.Now.ToString("h:mm:ss.fff"), (++invokeCount).ToString());
if (invokeCount == maxCount)
{
// 重置计数器和信号主键。
invokeCount = 0;
autoEvent.Set();
}
}
}
}
public void DoWork()
{
// 对任务进行排队。
System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(SomeLongTask));
// 对另一个任务进行排队。
System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(AnotherLongTask));
}
private void SomeLongTask(Object state)
{
// 插入代码以执行长任务。
}
private void AnotherLongTask(Object state)
{
// 插入代码以执行长任务。
}
public class TestThreading
{
private System.Object lockThis = new System.Object();
public void Process()
{
lock (lockThis)
{
// 访问线程敏感的资源。
}
}
}
class Program
{
static AutoResetEvent autoEvent;
static void DoWork()
{
Console.WriteLine("3、工作线程已启动, 正在等待事件...");
autoEvent.WaitOne();
Console.WriteLine("5、工作线程已重新激活, 现在退出...");
Console.Read();
}
static void Main()
{
autoEvent = new AutoResetEvent(false);
Console.WriteLine("1、主线程启动辅助线程...");
Thread t = new Thread(DoWork);
t.Start();
Console.WriteLine("2、主线程休眠1秒...");
Thread.Sleep(1000);
Console.WriteLine("4、主线程向辅助线程发出信号...");
autoEvent.Set();
}
}