7

Currently I'm porting a software from Windows to Mac OS X in C++.

In Windows, there's an abandoned state in global named mutex which means that current owner process of the mutex is gone without releasing the mutex. (It will likely be caused by application crash)

Because of abandoned state exists, trying to lock for abandoned mutex will not cause deadlock.
If there's no abandoned state, it will wait forever for a mutex which is not owned by anyone.

There's another approach by using timeout to assume the mutex is abandoned if unable to obtain the mutex for certain time, but it is not a perfect solution compared against abandoned mutex way. In the worst case, accidentally two processes can access to the object locked by the mutex.

Is there any mutex support abandoned state in Mac OS X/Linux?

I researched for the boost library, the boost library has a named mutex, but that one is based on a shared file so it does not have abandoned state.

Please give me some advise.

Aki24x
  • 998
  • 1
  • 11
  • 26
  • 2
    Just posting links not definitive answer - but you might look into pthread muteness including robust mutexes. See the comments in this topic: http://stackoverflow.com/questions/4424193/what-happens-to-mutex-when-the-thread-which-acquired-it-exits – Corbell May 28 '14 at 23:00
  • Hi orpheist! Thanks for your answer! I took a look at robust pthread, but it does not look like support interprocess locking... I started feeling a solution might be semaphore (I could not find if it's robust like robust pthread), or using file locking (which will be released upon process crashing). I need more research... Thanks a lot, anyway! – Aki24x May 29 '14 at 18:20

2 Answers2

4

Well maybe a little late but you can use the pthread_mutexattr_t to set your mutex attribute to be shared between pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED); API. This mutex value needs to be shared between processes by storing it into a named shared memory.

Here is a code snippet:

int key = ftok(NAMED_MEMORY, ID_TAG);
if (-1 == key)
{
    printf("Unable to name shared memory\n");
    exit(1);
}

// Create the segment exclusively (if the segment already exists then a combination of IPC_CREAT | IPC_EXCL returns an error EEXIST)
int m_iShmid = shmget(key, TOTAL_SIZE, READ_WRITE_PERMISSIONS | IPC_CREAT | IPC_EXCL);
if (m_iShmid < 0)
{
    if (EEXIST == errno)
    {
        // if the shared memory already exists we only fetch the id to that memory
        m_iShmid = shmget(key, TOTAL_SIZE, READ_WRITE_PERMISSIONS);
    }
    if (m_iShmid < 0)
    {
        printf("Unable to create shared memory - %s\n",strerror(errno));
        exit(1);
    }
    else
        printf("Attached to the existing shared memory\n");
}
else
    printf("Created new shared memory\n");

// Now we attach the segment to our data space.
mutex = reinterpret_cast<pthread_mutex_t*>(shmat(m_iShmid, NULL, 0));
if (reinterpret_cast<pthread_mutex_t*>(-1) ==  mutex)
{
    printf("Unable to attach shared memory to the process - %s\n",strerror(errno));
    exit(1);
}

// Now we can set this mutex to be shared between processes
pthread_mutex_t* mutex;
pthread_mutexattr_t mutexAttr;
ret = pthread_mutexattr_init(&mutexAttr);
if(ret != 0)
{
    printf("pthread_mutexattr_init failed - err=%d\n",ret);
    exit(1);
}
ret = pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED);
if(ret != 0)
{
    printf("pthread_mutexattr_setpshared failed - err=%d\n",ret);
    exit(1);
}
ret = pthread_mutexattr_setrobust_np(&mutexAttr, PTHREAD_MUTEX_ROBUST_NP);
if(ret != 0)
{
    printf("pthread_mutexattr_setrobust_np failed - err=%d\n",ret);
    exit(1);
}
ret = pthread_mutex_init(mutex, &mutexAttr);
if(ret != 0)
{
    printf("pthread_mutex_init failed - err=%d\n",ret);
    exit(1);
}
// ------ Use the mutex from here on between processes
seaborg
  • 51
  • 6
2

Given that the only answer here uses the ancient ftok()/shmget() approach to acquiring shared memory, I'm going to point you at a library I develop and maintain:

https://github.com/cubiclesoft/cross-platform-cpp

Specifically, you want the 'sync/sync_mutex.*' and 'sync/sync_util.*' files. You get Windows, Mac, Linux, and probably a few variants of those with a single Sync::Mutex class using modern POSIX pthreads and POSIX shared memory for named objects on *NIX-style OSes. The code also handles scenarios such as only letting one thread create and initialize an object and other threads wait until the object is fully initialized before continuing on.

The Sync portion of the library used to use POSIX semaphores, but I discovered that those are quite broken on some OSes while shared memory and pthreads share wider support on those same OSes.

As far as abandoned states go, the OS itself has to take ownership of synchronization objects to handle that particular scenario. That is, a process exits and all acquired synchronization objects get marked as abandoned. The Windows kernel generally handles cleanup of synchronization objects when a process exits. Other OS kernels won't/can't do that. One possible option is to write a system service or driver for other OSes whose sole purpose is to handle abandoned states and clean up and reinitialize objects. Of course, if you figure out a nifty way to handle abandoned objects from within an application itself, let me know/submit a patch/etc.

CubicleSoft
  • 1,614
  • 14
  • 17