I have a technical application that interacts with different hardware components: measurement devices, sensors, custom hardware. These use dedicated interfaces like USB, serial ports, TCP/IP communication and others. Most of these devices' implementations wrap a request/response pattern: Send something to the device and wait for a response to perform a specific task.
The software now has to perform both long and short tasks that all involve communicating with these hardware components. In order to "keep the GUI responsive", I wrapped all long (and even the shorter) tasks in worker threads.
All of that works fine as long as one hardware component is exclusively used by one thread. My trouble begins when e.g. a "background task" uses the same hardware component that is also used by some "long task": Either the related resources cannot be aquired, or the different threads' communications interfere with each other, breaking the request/response pattern of the related resources. Another problem arises when a device has long-lasting init sequences when connecting to it: In these cases it's tempting to just keep a connection to some hardware open, which one the other hand locks out other threads from accessing that hardware longer than needed.
To solve these problems, I have a few solutions in place:
use a global object that is initialized once, and wrap the request/response part into a mutex that protects from interrupting the request/response sequence.
Problem here: The mutex part can create problems if there is some kind of event processing between request/response, e.g. with TCP/IP protocols.
Use a new instance of a hardware object's controller class whenever needing to communicate with that device.
Problems here:
- Overhead in initialization/connecting, which is done over and over again
- must be possible to have simultaneous connections to the hardware or one must wait until hardware can be connected again, which creates quite some overhead and can create subtle bugs.
wrap all stuff related to a specific hw component in a seperate worker thread, and use that from other worker threads.
Problems here:
- additional complexity when connecting workers to each other
- also needs mutexes or other synchronisation methods with are not obvious from the code interacting with this worker, thus error-prone and hard to debug
I am using Qt / C++ in my software, and typically I use signal/slot for communicating between different threads. However I believe that my use case is not too specific for this framework and programming language, and patterns from other languages might provide nice ideas and solutions ...
My question: What kind of patterns could I use to wrap my hardware components' objects in a consistent way, so I can access them from multiple worker threads while solving my problems described above?