
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"); }
participants (1)
-
Sam Partington