简体   繁体   中英

C#/.NET application design with multi-threading/tasks

I want to design an application that provides some bi-directional communcation between two otherwise completely separate systems. (bridge)
One of them can call my application via web services - the other one is a piece of 3rd party hardware. It speaks RS232. Using a RS232<->ETH transceiver we manage to talk to the piece of hardware using TCP.

The program has the following requirements .

  • There is a main thread running the "management service". This might be a WCF endpoint or a self-hosted webapi REST service for example. It provides methods to start new worker instances or get a list of all worker instances and their respective states.
  • There are numerous "worker" threads. Each of them has a state model with 5 states.
  • In one state for example a TCP listener must be spawned to accept incoming connections from a connected hardware device (socket based programming is mandatory). Once it gets the desired information it sends back a response and transitions into the next state.
  • It should be possible from the main (manager) thread to (gracefully) end single worker threads (for example if the worker thread is stuck in a state where it cannot recover from)

This is where I am coming from:

  • I considered WCF workflow services (state model activity) however I wasn't sure how to spawn a TcpListener there - and keep it alive. I do not need any workflow "suspend/serialize and resume/deserialize" like behavior.
  • The main thread is probably not that much of a concern - it just has to be there and running. It's the child (background) threads and their internal state machine that worry me.
  • I tried to wrap my mind around how Tasks might help here but I ended up thinking threads are actually a better fit for the task

Since there has been a lot of development in .NET (4+) I am not sure which approach to follow ... the internet is full of 2005 to 2010 examples which are probably more than just outdated. It is very difficult to separate the DOs from the DONTs.

I'm glad for any hints.

UPDATE : Okay I'll try to clarify what my question is...

I think the easiest way is to provide some pseudo code.

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

The management head (= wcf service) offers a few methods

  • StartCommunicator() to start new worker threads doing the actual work with 5 states
  • Shutdown() to shut down the whole application, letting all worker threads finish gracefully (usually a question of minutes)
  • GetAllCommunicatorInstances() to show a summary of all worker threads and the current state they are in.
  • DestroyCommunicatorInstance(port) to forcefully end a worker thread - for example if communicator is stuck in a state where it cannot recover from.

Anyway I need to spawn new background threads from the "management" service (StartCommunicator method).

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
}

So the question is whether my approach will take me anywhere or if I'm completely on the wrong track.
How do I implement this best? Threads? Tasks? Is while(true) a valid thing to do? How do I interact with the communicator instances from within my "management service"? What I am looking for is an annotated boiler plate kind of solution :)

My suggestion would be to use a ASP.NET Web API service and mark the Controller actions as async. From that point on, use Tasks as much as possible and when you end up with blocking IO the HTTP server will not be blocked. Personally, I would avoid Threads until you are absolutely sure that you can't achieve the same thing with Tasks.

I would recommend looking at using a thread pool. This will help with managing resources and make for more efficient use of the resources.

As far as terminating threads, thread pool threads are background workers and will be terminated when your service stops, however, from your description above that is not sufficient. Your threads should always have the ability to receive a message asking them to terminate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM