Threaded resource managers

The resource managers presented in this book are single-threaded. The resource manager part of the code runs with one thread—other threads, not directly related to the resource manager framework, may also be present.

This was done for simplicity, and because the examples presented here don't need multiple resource manager threads because:

  1. the QNX Neutrino resource manager library enforces singled-threaded access to any resource that shares an attributes structure,
  2. all of the I/O and Connect function outcalls are run to completion and do not block, and
  3. simplicity.

Single-threaded access to resources that share an attributes structure means that if two or more client threads attempt to access a resource, only one of the threads can make an outcall at a time. There's a lock in the attributes structure that the QNX Neutrino library acquires before making an outcall, and releases when the call returns.

The outcalls “running to completion” means that every outcall is done “as fast as possible,” without any delay or blocking calls. Even if the resource manager was multi-threaded, and different attributes structures were being accessed, things would not be any faster on a single-processor box (though they might be faster on an SMP box).

A multi-threaded resource manager may be a lot more complex than a single-threaded resource manager. It's worthwhile to consider if you really need a multi-threaded resource manager. The complexity comes from:

  1. handling unblock pulses (see Getting Started with QNX Neutrino),
  2. terminating the resource manager, and
  3. general multi-threaded complexity.

Handling unblock pulses was covered extensively in my previous book—the short story is that the thread that's actively working on the client's request probably won't be the thread that receives the unblock pulse, and the two threads may need to interact in order to abort the in-progress operation. Not impossible to handle, just complicated.

When it comes time to terminate the resource manager, all of the threads need to be synchronized, no new requests are allowed to come in, and there needs to be a graceful shutdown. In a high-availability environment, this can be further complicated by the need to maintain state with a hot standby (see the High Availability chapter).

Finally, multi-threaded designs are generally more complex than single-threaded designs. Don't get me wrong, I love to use threads when appropriate. For performing multiple, concurrent, and independent operations, threads are wonderful. For speeding up performance on an SMP box, threads are great. But having threads for the sake of having threads, and the accompanying synchronization headaches, should be avoided.