.NET 多线程和线程间的通信






3.21/5 (26投票s)
2002年12月30日
3分钟阅读

164620

1736
本文解释了主线程和工作线程之间的消息传递
多线程 - 杀手级工具
.NET 线程是一个强大的工具,可用于需要高可伸缩性的应用程序。如果没有使用Threading
命名空间,我怀疑我们是否能够释放.NET平台的真正力量。 所有后端应用程序,如数据库服务器、Web服务器、队列管理系统以及 Word、Excel 等应用程序都使用多线程。
在 .NET 中,完美的 OO 平台线程也作为对象创建和访问。
主线程和多个工作线程模型被许多应用程序使用。在此模型中,父线程根据所需的服务启动许多工作线程。所有工作线程都执行相同的工作,但在父线程预定义的上下文中执行。 例如,在数据库服务器应用程序中,每当连接新客户端时,就会创建一个新的工作线程。这是一个过于简化的例子,实际逻辑比这更复杂。
在此模型中,工作线程可能希望向主线程发送消息以报告其进度。 此消息传递的关键部分是通知代码的消息应由父线程执行,而不是由工作线程执行。
此项目可用作完成上述内容的工具。 这是一个线程池管理系统,启用了通信功能。 有一个名为ThreadManager
的类,其客户端可以定义线程数、工作线程应调用的方法以及通知父线程时应调用的方法。
该类实现了如下所示的interface
public interface IThreadManager
{
int ThreadCount
{
get;
}
void SetRunMethod(MethodNoParam Run);
void SetMessageReceiveMethod(MethodWithParam Receive);
void Start();
void Stop();
void SendMessageToMain(object Message);
}
- 要启动的线程数在构造函数中指定。
SetRunMethod
期望一个委托,该委托指向工作线程启动时执行的代码。SetMessageReceiveMethod
用于指定Main
线程执行的消息接收代码SendMessageToMain
由工作线程调用,当它想向主线程发送消息时。
// Specify no of worker threads to start
_ThreadMgr = new ThreadManager(Convert.ToInt32
(ThreadCount.Value.ToString()));
MethodNoParam _RunMethod = new
MethodNoParam(this.ThreadMehod);
MethodWithParam _ReceiveMethod = new
MethodWithParam(this.CallBackMethod);
// Code executed by Worker threads
_ThreadMgr.SetRunMethod(_RunMethod);
// Message receiving method- Main thread
_ThreadMgr.SetMessageReceiveMethod(_ReceiveMethod);
_ThreadMgr.Start();
MethodNoParam
和MethodWithParam
是在全局级别定义的委托。
当工作线程启动时,它们会增加在客户端定义的NoOfRecordsUpdated
变量,直到它达到RecordsToBeProcessed
。 工作线程在每次更新后,通过调用SendMessageToMain
通知主线程。 任何数据都可以传递给Main
线程,具体实现留给客户端。 在这种情况下,客户端将更新的记录数发送给Main
。
private void ThreadMehod()
{
try
{
while (true)
{
Monitor.Enter(this);
if (RecordsProcessed >= RecordsToBeProcessed)
{
Monitor.Exit(this);
break;
}
else
{
RecordsProcessed +=20;
Monitor.Exit(this);
_ThreadMgr.SendMessageToMain(RecordsProcessed);
Thread.Sleep(500);
}
}
}
catch
{
}
}
主线程提取工作线程传递的数据。 在这种情况下,它会更新进度条。
private void CallBackMethod(object State)
{
this.Invoke(_ShowCurrentState,new object[]{State});
//System.Diagnostics.Debug.WriteLine
// (Thread.CurrentThread.Name);
}
通过取消注释第二行,可以将执行此代码的线程确认为 Main。
ThreadManager
正在使用基于队列的机制进行消息传递。
对于其他设计模式,例如一个线程依赖于另一个线程的管道模型,我们可以使用内置函数,例如Wait
、Join
等。应用程序定义了两个委托,由客户端使用。 客户端是一个 Windows 窗体,它具有应由主线程和工作线程执行的方法。 通过使用Invoke
方法,将所谓的Main
线程接收到的消息传递给 UI 线程。 可以在 Windows 窗体上创建的所有视觉对象都从Control
类继承。 Control 类公开了接受委托的Invoke
方法。
下面显示了DispatchMessage
方法。
public void DisptachMessage()
{
while(m_Started)
{
Monitor.Enter(this);
while(m_Messages.Count > 0)
{
m_MessageReceiveMethod(m_Messages.Dequeue());
}
Monitor.Exit(this);
Thread.Sleep(100);
}
}
由于此示例中的Main
线程一直在调度消息,因此不鼓励将 UI 线程用于此目的。
private void CallBackMethod(object State)
{
this.Invoke(_ShowCurrentState,new object[]{State});
}
主线程接收到的消息(例如,该示例中更新的记录)将传递给 UI,UI 将更新进度条。
当需要异步通知并且其发起的线程不是问题时,我们可以使用委托的BeginInvoke
方法。
参考文献
- .NET 委托 C# 睡前故事
- Jeffrey Richter 著的《应用 Microsoft .NET Framework 编程》