This is on Linux but ideally I'd like a POSIX compliant solution.
I have two threads each of which is able to write to a hardware bus via an API function. Only one thread is allowed to write to the bus at any given time, and after a bus write, the bus must not be written to for a given time of the order of several hundred milliseconds.
Both threads are implemented as state machines.
The obvious solution is to use a mutex to serialise access to the bus, set a counter or timestamp, and have the state machine unlock the mutex after the appropriate time has expired.
This seems a little fragile to me. If a future maintenance developer incorrectly modifies the state machine, the mutex might not get released, causing hard-to-diagnose deadlocks.
Is there an API call that locks a mutex, but automatically unlocks it after a given timeout? Google reveals pthread_mutex_timedlock(), but this isn't quite the same thing.
I'm not aware of any pthreads API which allows locks to be automatically released.
Personally I'd try and serialise access to the bus through a single thread to avoid these complications. If that thread maintains an input queue and other threads post their requests to it, then it could do whatever serialisation and conflict resolution it wished, and this also makes it easier to implement the delay before further access. As long as you're careful not to use any blocking functions in this thread your only real failure case is that it might be terminated accidentally.
If you need to both read and write from the bus, you can give every thread an input queue and have worker threads post a "read request" to the IO thread and then wait for the response to be posted back to its own input queue. If there's only ever one outstanding request for a thread then you don't really need a queue, a simple condition variable and a pointer to the structure to fill in would probably work fine.
If you definitely want two threads to share the resource then I think you're always going to have a risk of the mutex becoming locked up. Even if you set a timer and forcibly release the mutex after a fixed time, that could simply cause different bugs where a thread goes on to use the resource believing it has the lock when in fact it's held by another thread entirely. Ultimately you're trying to plan robustness against future programming errors, which is a fine aim but there's a limit - mutexes are just something one has to be careful with.
I suggest your best approach, if you must go the mutex route, is to simply minimise the code which requires the mutex and avoid blocking calls within it. If you're implementing a state machine, try to ensure that the mutex doesn't have to stay locked between state transitions. If at all possible, scope your mutex locks so that they're only held for the duration of a single function call at some level in your call chain - this makes it a lot easier to spot lock/unlock mismatches by eye. If you're using C++ then use RAII to make releasing your locks more reliable.
But once again, I think you'll find life a lot easier serialising your requests in some way, typically by declaring one thread the arbiter (either one of the existing threads or a new one).
How about having a timestamp of last bus access in shared (and mutex-covered) memory? Each write would than look like this:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With