65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.21/5 (26投票s)

2002年12月30日

3分钟阅读

viewsIcon

164620

downloadIcon

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();

MethodNoParamMethodWithParam 是在全局级别定义的委托。

当工作线程启动时,它们会增加在客户端定义的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 正在使用基于队列的机制进行消息传递。

对于其他设计模式,例如一个线程依赖于另一个线程的管道模型,我们可以使用内置函数,例如WaitJoin 等。应用程序定义了两个委托,由客户端使用。 客户端是一个 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方法。

参考文献

© . All rights reserved.