用创建线程的方法也可以达到异步的效果(个人认为这个才是最实质的异步方式),首先,先来学习一下涉及到的类和方法
ThreadStart 委托
[C#]
[Serializable]
public delegate void ThreadStart();
这个委托只支持返回值为void类型的方法,所以个人觉得比较有局限。当然,可以用一些方法来做到传入参数。
创建线程时,将使用采用 ThreadStart 委托作为其唯一参数的构造函数创建 Thread 类的新实例。但线程在调用 Start 方法前不会开始执行。调用 Start 后,将从由 ThreadStart 委托引用的方法的第一行开始执行。
所以创建线程的方法是:
m_WorkerThread = new Thread(new ThreadStart(this.WorkerThreadFunction));
线程启动的方法:
m_WorkerThread.Start();
ManualResetEvent 类(MSDN描述)
通知一个或多个正在等待的线程已发生事件。
ManualResetEvent 允许线程通过发信号互相通信。通常,此通信涉及一个线程在其他线程进行之前必须完成的任务。
当线程开始一个活动(此活动必须在其他线程进行之前完成)时,它调用 Reset 将 ManualResetEvent 设置为非终止状态。此线程可被视为控制 ManualResetEvent。调用 ManualResetEvent 上的 WaitOne 的线程将阻塞,并等待信号。当控制线程完成活动时,它调用 Set 以发出等待线程可以继续进行的信号。并释放所有等待线程。
一旦它被终止,ManualResetEvent 将保持终止状态,直到它被手动重置。即对 WaitOne 的调用将立即返回。
可以通过将布尔值传递给构造函数来控制 ManualResetEvent 的初始状态,如果初始状态处于终止状态,为 true;否则为 false。
ManualResetEvent 还可以和静态(在 Visual Basic 中为 Shared)WaitAll 和 WaitAny 方法一起使用。
使用 ManualResetEvent 类使某个线程等待,直到某个事件通过调用 ManualResetEvent.Set 将其置于已发信号的状态为止。ManualResetEvent 将始终保持已发信号的状态,直到通过 Reset 方法将其显式设置为未发信号的状态为止。对于任何数目的等待线程或随后通过调用一个等待函数开始等待指定的事件对象的操作的线程,它们都可以在该对象处于已发信号的状态时被释放。ManualResetEvent 与 Win32 CreateEvent 调用相对应,并将 bManualReset 参数指定为 true。
举例说明
先声明两个ManualResetEvent变量,然后创建新线程,执行一个方法,并将这两个事件传入这个方法中。一旦用户端触发了ManualResetEvent事件,则在工作线程中就会得到相应(manualResetEvent.WaitOne()),然后停止工作线程
代码如下:
//新线程开始
private void btnStartThread_Click(object sender, System.EventArgs e)
{
listBox1.Items.Clear();
btnStartThread.Enabled = false;
btnStopThread.Enabled = true;
//初始化事件
m_EventStopThread.Reset();
m_EventThreadStopped.Reset();
//创建工作线程实例
m_WorkerThread = new Thread(new ThreadStart(this.WorkerThreadFunction));
m_WorkerThread.Name = "Worker Thread Sample";
m_WorkerThread.Start();
}
//线程开始的方法
private void WorkerThreadFunction()
{
LongProcess longProcess;
longProcess = new LongProcess(m_EventStopThread, m_EventThreadStopped, this);
longProcess.Run();
}
private void StopThread()
{
if ( m_WorkerThread != null && m_WorkerThread.IsAlive ) //如果线程还存在
{
// 设置事件停止
m_EventStopThread.Set();
// 等待工作线程停止,或者工作线程结束
while (m_WorkerThread.IsAlive)
{
if ( WaitHandle.WaitAll(
(new ManualResetEvent[] {m_EventThreadStopped}),
100,
true) )
{
break;
}
Application.DoEvents();
}
}
ThreadFinished();
}
private void AddString(String s)
{
listBox1.Items.Add(s);
}
private void ThreadFinished()
{
btnStartThread.Enabled = true;
btnStopThread.Enabled = false;
}
public void Run()
{
int i;
String s;
for (i = 1; i <= 100; i++)
{
s = "Step number " + i.ToString() + " executed";
Thread.Sleep(400);
//更新UI
m_form.Invoke(m_form.m_DelegateAddString, new Object[] {s});
//如果停止事件被置位,则退出当前工作线程
if ( m_EventStop.WaitOne(0, true) )
{
m_EventStopped.Set();
return;
}
}
m_form.Invoke(m_form.m_DelegateThreadFinished, null);
}