There are different ways to do it, but if you are inclined to stick with POCO, you may want to look at the macchina.io (OSP portion) WebEvent implementation - it is essentially a pub/sub messaging framework. There's more there than what you need but it's relatively simple and architecturally you should be able to quickly tailor it to your needs. I have used it in production for many years and it works well; it will also be ported in an OSP-independent form to Poco for one of the next releases.
Client can be either (1) a web socket endpoint or (2) an in-process observer which can send (i.e. post events) data and/or subscribe (i.e. receive notifications) to one or more subjects (topics). You'll probably need many in-process observers and one remote endpoint.
The framework runs in two threads handling:
Each queue is dealt with in its own thread and there is a dotted-notation naming scheme for subject names, see here for details. Note that documentation only mentions WebSockets but naming works exactly the same for in-process observers and you may want or need a different naming scheme.
There's nothing in your problem statement to suggest that you require explicit multithreading. What I don't know about your C# application is if you are writing a Net Core app that is designed to be cross platform or not. That can limit what options you have.
Windows Only
Using the article here you use PInvoke to register for the SetConsoleCtrlHandler(...)
Win32 callback. That callback will let you know if your app received any of the events that would close your typical console app (Ctrl+C, Break, Close the console, logoff, shutdown). That lets you handle unexpected closing more gracefully.
You can create a Windows Service to enable your application to run even if someone is not logged in. This has the advantage of being able to use the Services control panel to start/stop your app.
Cross Platform
If you need to handle Linux/Mac as well as Windows, then using PInvoke is pointless since that is platform specific. However you can adopt a hybrid approach inspired by the Apache Tomcat developers.
They created a control interface on a separate TCP port that would allow an external tool to send a control message like shut down, restart, etc. For Windows, they had a Windows service that would handle starting the console app (Tomcat is a Java based web server you can run from your console) and sending the appropriate control messages when it was time to shut down. For Linux/Mac, they just had a script that did essentially the same thing that tied in to the daemon/service system.
Personal Experience
I created a separate console data processing app that was controlled a Windows service. This particular data processing app was used to monitor sensors and perform some fancy calculus so we could pinpoint problems. The data processing app sent the results to a semi-real time monitoring UI. The app had to work without stop for as long as the machine did. By creating a Windows Service that simply was there to control the data processing app, we could easily spin up a new instance if the old instance died for an unexpected reason. We could also monitor the app's memory usage and other health criteria.
One of the things we did in the console app was to make sure that there were no leftover resources being consumed by an instance that didn't shut down cleanly. It never happened in real life, but the importance of this process made us design for that case.
Control Protocol
You can use a simple control protocol based on UDP. C#'s socket API has asynchronous read/write which is why you don't need explicit multithreading. A lot of that is handled for you.
You just have to decide on the message format. If you use a control program, you can keep a reference to the running Process to monitor it's health and determine if it is running. Useful commands:
- Hang Up -- you can shut down now
- Reset -- go back to start up conditions (i.e. close your ports and reopen them)
- Heartbeat -- if you need to manage a process remotely
Best Answer
It sounds to me like they are leading you toward a semaphore solution. Semaphores are used to signal another thread that it's their turn. They are used much less frequently than mutexes, which I guess is why they think it's a good interview question. It's also why the example seems contrived.
Basically, you would create
m
semaphores. Each threadx
waits on semaphorex
then posts to semaphorex+1
after doing its thing. In pseudocode: