使用多线程/任务的C#/.NET应用程序设计



我想设计一个应用程序,在两个完全独立的系统之间提供一些双向通信(桥接)
其中一个可以通过web服务调用我的应用程序,另一个是第三方硬件。它会说RS232。使用RS232<->ETH收发器我们设法使用TCP与硬件进行通信。

该程序具有以下要求

  • 有一个主线程运行"管理服务"。例如,这可能是WCF端点或自托管的webapi REST服务。它提供了启动新工作实例或获取所有工作实例及其各自状态的列表的方法
  • 有许多"工作者"线程。它们中的每一个都有一个包含5个状态的状态模型
  • 例如,在一种状态下,必须派生TCP侦听器以接受来自连接的硬件设备的传入连接(基于套接字的编程是强制性的)。一旦它获得了所需的信息,它就会发回一个响应并转换到下一个状态
  • 应该可以从主(管理器)线程(优雅地)结束单个工作线程(例如,如果工作线程处于无法恢复的状态)

这就是我的来源:

  • 我考虑了WCF工作流服务(状态模型活动),但我不确定如何在那里生成TcpListener并使其保持活力。我不需要任何类似工作流"挂起/序列化和恢复/反序列化"的行为
  • 主线程可能没有那么大的问题——它只需要在那里并运行即可。让我担心的是子(后台)线程及其内部状态机
  • 我试着思考Tasks在这里可能会有什么帮助,但最终我认为线程实际上更适合这个任务

由于在.NET(4+)中进行了大量开发,我不确定该采用哪种方法。。。互联网上充斥着2005年至2010年的例子,这些例子可能不仅仅是过时的。将DO与DONT分开是非常困难的。

我很高兴得到任何提示。

更新:好的,我会努力澄清我的问题是什么…

我认为最简单的方法是提供一些伪代码。

public static void Main()
{
// Start self-hosted WCF service (due to backwards compatibility, otherwise I'd go with katana/owin) on a worker thread
StartManagementHeadAsBackgroundThread();
// Stay alive forever
while(running)
{
// not sure what to put here. Maybe Thread.Sleep(500)?
}
// Ok, application is shutting down => somehow "running" is not true anymore.
// One possible reason might be: The management service's "Shutdown()" method is being called
// Or the windows service is being stopped...
WaitForAllChildrenToReachFinalState();
}
private static void StartManagementHeadAsBackgroundThread()
{
ThreadStarter ts = new ThreadStarter(...);
Thread t = new Thread(ts);
t.Start();
}

管理主管(=wcf服务)提供了几种方法

  • StartCommunicatior()启动新的工作线程,用5种状态完成实际工作
  • Shutdown()关闭整个应用程序,让所有工作线程正常完成(通常是几分钟的问题)
  • GetAllCommunicatiorInstances()显示所有工作线程及其当前状态的摘要
  • DestroyerCommunicatorInstance(端口)强制结束工作线程-例如,如果communicator处于无法恢复的状态

无论如何,我需要从"管理"服务(StartCommunicator方法)生成新的后台线程。

public class Communicator
{
private MyStateEnum _state;
public Communicator(int port)
{
_state = MyStateEnum.Initializing;
// do something
_state = MyStateEnum.Ready;
}
public void Run()
{
while(true)
{
// again a while(true) loop?!
switch(_state):
{
case MyStateEnum.Ready:
{
// start TcpListener - wait for TCP packets to arrive.
// parse packets. If "OK" set next good state. Otherwise set error state.
}
}
if(_state == MyStateEnum.Error) Stop();
break;
}
}
public void Stop()
{
// some cleanup.. disposes maybe. Not sure yet.
}
}
public enum MyStateEnum
{
Initializing, Ready, WaitForDataFromDevice, SendingDataElsewhere, Done, Error
}

所以问题是我的方法是否会带我去任何地方,或者我是否完全走错了轨道
如何最好地实现这一点?线程?任务?while(true)是一件有效的事情吗?我如何从我的"管理服务"中与通信器实例进行交互?我正在寻找的是一种带注释的锅炉板类型的解决方案:)

我的建议是使用ASP.NET Web API服务并将控制器操作标记为异步。从那时起,尽可能多地使用Tasks,当您最终阻塞IO时,HTTP服务器将不会被阻塞。就我个人而言,我会避免线程,直到你完全确定你不能用任务实现同样的事情。

我建议考虑使用线程池。这将有助于管理资源,并使资源得到更有效的利用。

至于终止线程,线程池线程是后台工作者,当您的服务停止时,线程池将被终止,但是,从您上面的描述来看,这是不够的。您的线程应该始终能够接收到要求它们终止的消息。

最新更新