Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++11 interprocess atomics and mutexes

I have a Linux program which spawns several processes (fork) and communicates through POSIX Shared Memory. I'd like to have each process allocate an id (0-255). My intention is to place a bitvector in the shared memory region (initialized to zero) and atomically compare and swap a bit to allocate an id.

Is there a c++11-friendly way to do this? Can I create an atomic bitset? Can I use a mutex across processes? How do I assure that constructors get called once and only once across all processes?

like image 619
dschatz Avatar asked Oct 31 '12 15:10

dschatz


2 Answers

The C++11 threading primitives (mutexes, atomics, etc) are threading primitives. The C++ standard doesn't reference processes, and most of these tools don't interoperate across processes.

The only mention of processes in the standard is in a non-normative notation that says that lock-free atomics are intended to be OK for IPC:

Operations that are lock-free should also be address-free. That is, atomic operations on the same memory location via two different addresses will communicate atomically. The implementation should not depend on any per-process state. This restriction enables communication by memory that is mapped into a process more than once and by memory that is shared between two processes.

Outside of this non-normative notation, the threading primitives are not intended to be a means of achieving inter-process communication. The behavior of such objects when placed in shared memory (aside from lock-free atomics as noted above) is undefined.

like image 104
Nicol Bolas Avatar answered Oct 08 '22 17:10

Nicol Bolas


You can use mutex inside of shared memory block, but the mutex must be declared as SHARED, therefore is not unusual using mutexes inside of share memory, u can make own class, it is very simple:

class Mutex {
private:
    void *_handle;
public:
    Mutex(void *shmMemMutex,  bool recursive =false, );
    virtual ~Mutex();

    void lock();
    void unlock();
    bool tryLock();
};

Mutex::Mutex(void *shmMemMutex, bool recursive)
{
    _handle = shmMemMutex;
    pthread_mutexattr_t attr;
    ::pthread_mutexattr_init(&attr);
    ::pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
    ::pthread_mutexattr_settype(&attr, recursive ? PTHREAD_MUTEX_RECURSIVE_NP : PTHREAD_MUTEX_FAST_NP);

    if (::pthread_mutex_init((pthread_mutex_t*)_handle, &attr) == -1) {
        ::free(_handle);
        throw ThreadException("Unable to create mutex");
    }
}
Mutex::~Mutex()
{
    ::pthread_mutex_destroy((pthread_mutex_t*)_handle);
}
void Mutex::lock()
{
    if (::pthread_mutex_lock((pthread_mutex_t*)_handle) != 0) {
        throw ThreadException("Unable to lock mutex");
    }
}
void Mutex::unlock()
{
    if (::pthread_mutex_unlock((pthread_mutex_t*)_handle) != 0) {
        throw ThreadException("Unable to unlock mutex");
    }
}
bool Mutex::tryLock()
{
    int tryResult = ::pthread_mutex_trylock((pthread_mutex_t*)_handle);
    if (tryResult != 0) {
        if (EBUSY == tryResult) return false;
        throw ThreadException("Unable to lock mutex");
    }
    return true;
}
like image 10
doc_ds Avatar answered Oct 08 '22 15:10

doc_ds