Boost logo

Boost :

Subject: [boost] [interprocess] named_mutex issues
From: Sam Partington (sam.partington_at_[hidden])
Date: 2011-02-17 09:32:26


Hello,

I recently found a bug in my own implementation of named_mutex (which
uses record locking) and thought that it was high time that I
investigated the boost implementation to replace my own version.

Unfortunately I found the documentation extremely unclear about what
guarantees named_mutex makes under certain circumstances. e.g.

1) What happens if I call boost::named_mutex::remove whilst I have it
opened or locked in another process.

2) What happens if the process terminates when a mutex is locked
without calling the destructors? (e.g. Ctrl-C or seg fault)

3) The docs describe the mutex as "A mutex with a global name, so it
can be found from different processes", what about other users? Is
this intended to work or not?

4) Does ~named_mutex unlock the mutex if it is still locked?

5) What names are valid? Slashes, spaces, etc?

To find these out I had to follow the implementation right down
through many layers of indirection and compile time switches to
discover what the underlying synchronisation mechanism was (POSIX
Semaphore on linux). And of course write a couple of examples to test
my interpretations.

The answers on linux at least are

1) It removes the semaphore, but as it's link count is not 0 it
remains and the other process keeps it's lock. Meanwhile another
process can then create a new named_mutex of the same name AND lock
it. Essentially messing up the whole mutual exclusion policy as two
processes lock the same mutex. I don't think there is a (reasonable)
solution to this and IMO this potential pitfall needs to be made clear
in the docs.

2) If the process does not shutdown cleanly whilst the mutex is locked
it doesn't release the lock. Another process could in theory create
the lock again and unlock it again. But I don't know how it could
detect this situation, unless some process is the 'master' and can
initialise all state to a known state. (This doesn't apply in my use
case for example)

3) This doesn't really work because the process umask means that the
semaphore is likely to be created 0755 and can't be opened by other
users. They get permission denied even if the mutex is not locked. a
simple { int oldmask = umask(0); ... umask(oldmask); around the
sem_open would solve this.

4) No the mutex is not unlocked if destroyed when locked. I thought
this was a bit surprising. Unfortunately I don't suppose you can
really change that now, but it should de documented.

5) slashes must not be used to conform with POSIX, and it must not be
longer than MAX_PATH other platforms I don't know.

I appreciate with so many platforms and different implementations it
must be very difficult to document these things. But at least it
should not be so hard to find out what the underlying mechanism is.

Ultimately though the whole point of an abstraction library like this
is to make it so that you don't have to worry about the specifics of
the implementation or the platform, but to provide a common set of
guarantees and specifications. Without those the abstraction layer is
kind of missing the point.

Another thing I found on the way is that strictly speaking the call to
sem_open is undefined behaviour (at least according to POSIX.4.
Programming for the real world by Bill O. Gallmeister). As you should
not pass any of O_RDONLY O_WRONLY or O_RDWR. See

http://books.google.co.uk/books?id=4Kb_1sKprCMC&lpg=PA432&ots=v7mIM0xVHS&dq=O_RDONLY%20sem_open%20POSIX&pg=PA431#v=onepage&q=O_RDONLY%20sem_open%20POSIX&f=false

http://preview.tinyurl.com/5slzcu6

Although another reference I found suggested that it would be merely
unspecified not undefined.

I guess I will have to stick with my own implementation because 2) is
incompatible with my requirements.

Sam

PS I tested this on boost 1.45 with the following code :

#include <boost/interprocess/sync/named_mutex.hpp>
#include <iostream>
#include <string>

using namespace boost::interprocess;

int main()
{
    named_mutex m(open_or_create, "named_mutex_test");
    m.lock();
    std::cout << "Lock obtained, type something + press enter:";
    std::string s;
    std::cin >> s;
    m.unlock();
    named_mutex::remove("named_mutex_test");
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk