Well, one possibility is that the resource you're using lends itself naturally to recursive algorithms.
Think of searching a binary tree, while preventing everyone else from using (especially modifying) the tree out with a mutex.
If you use a recursive mutex, you can simply have one function search()
that you pass the root node in to. It then recursively calls itself as per a normal binary tree search but the first thing it does in that function is to lock the mutex (while this looks like Python, that's really just because Python is an ideal basis for pseudo-code):
def search (haystack, mutex, needle):
lock mutex recursively
if haystack == NULL:
unlock mutex and return NULL
if haystack.payload == needle:
unlock mutex and return haystack
if haystack.payload > needle:
found = search (haystack.left, mutex, needle)
else:
found = search (haystack.right, mutex, needle)
unlock mutex and return found
The alternative is to separate the mutex lock and search into two separate functions like search()
(public) and search_while_locked()
(most likely private):
def private search_while_locked (haystack, needle):
if haystack == NULL:
return NULL
if haystack.payload == needle:
return haystack
if haystack.payload > needle:
return search_while_locked (haystack.left, needle)
return search_while_locked (haystack.right, needle)
def search (haystack, mutex, needle):
lock mutex non-recursively
found = search_while_locked (haystack.right, needle)
unlock mutex and return found
While that sort of defeats the elegance of the recursive solution, I actually prefer it since it reduces the amount of work that needs to be done (however small that work is, it's still work).
And languages that lend themselves easily to public/private functions can encapsulate the details well. The user of your class has no knowledge (or need of knowledge) as to how you do things within your class, they just call the public API.
Your own functions, however, have access to all the non-public stuff as well as full knowledge as to what locks need to be in place for certain operations.
Another possibility is very much related to that but without being recursive.
Think of any useful operation you may want users to perform on your data which requires that no-one else be using it during that time. So far, you have just the classic case for a non-recursive mutex. For example, clearing all of the entries out of a queue:
def clearQueue():
lock mutex
while myQueue.first <> null:
myQueue.pop()
unlock mutex
Now let's say you find that rather useful and want to call it from your destructor, which already locks the mutex:
def destructor():
lock mutex
clearQueue()
doSomethingElseNeedingLock()
unlock mutex
Obviously, with a non-recursive mutex, that's going to lock up on the first line of clearQueue
after your destructor calls it, which may be one reason why you'd want a recursive mutex.
You could use the afore-mentioned method of providing a locking public function and a non-locking private one:
def clearQueueLocked():
while myQueue.first <> null:
myQueue.pop()
def clearQueue():
lock mutex
clearQueueLocked():
unlock mutex
def destructor():
lock mutex
clearQueueLocked():
doSomethingElseNeedingLock()
unlock mutex and return
However, if there are a substantial number of these public/private function pairs, it may get a little messy.