.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 编程》
