Удаление boost interprocess_mutex, когда другой процесс может его использовать - PullRequest
0 голосов
/ 05 июня 2018

Я пытаюсь использовать interprocess_mutex с managed_windows_shared_memory.В моем проекте несколько процессов создают экземпляр class A в следующем коде.

using namespace boost::interprocess;

class A
{
    managed_windows_shared_memory* _shm;
    interprocess_mutex* _mtx;
}
A::A()
{
    _shm = new managed_windows_shared_memory{ open_or_create, "shm", 1024 };
    _mtx = _shm->find_or_construct<interprocess_mutex>("mtx")();
}
A::~A()
{
    delete _mtx;
    delete _shm;
}

Я вижу, что безопасно вызывать delete _shm; в ~A(), так как managed_windows_shared_memory будетуничтожается только тогда, когда каждый процесс, использующий его, уничтожает объект managed_windows_shared_memory, как написано в doc .

Однако я не уверен, безопасно ли вызывать delete _mtx; в ~A() doc для interprocess_mutex не упоминается, уничтожен ли он или нет, даже если другие процессы имеют ссылающиеся на него объекты.

Я искал this и я предполагаю, что мой вариант - использовать boost::interprocess::shared_ptr в этом случае.Я здесь?Это вариант, который я должен взять?

Ответы [ 2 ]

0 голосов
/ 14 июля 2018

Во-первых, указатель, который указывает на interprocess_mutex, выделенный в общей памяти, нельзя уничтожить с помощью delete напрямую, поскольку указатель указывает на некоторый адрес в адресном пространстве процесса, который отображает в область общей памяти, где фактически находится мьютекс.Поэтому в следующем коде выполнение строки delete mtx дает сбой.

#include <boost/interprocess/managed_windows_shared_memory.hpp>

using namespace boost::interprocess;

int main()
{
    managed_windows_shared_memory shm{ open_or_create, "shm", 1024 };

    interprocess_mutex *mtx = shm.find_or_construct<interprocess_mutex>("gMutex")();

    delete mtx; // ***** CRASH *****
}

Чтобы правильно уничтожить созданный объект с помощью указателя, вызовите shm.destroy_ptr(mtx) вместо delete mtx.


Во-вторых, скомпилировав следующий код и выполнив его дважды на двух отдельных консолях, можно проверить, что уничтожение interprocess_mutex с помощью destroy_ptr, пока другой процесс блокирует мьютекс, не приводит к сбою.Кроме того, процесс, удерживающий блокировку, может безопасно разблокировать мьютекс впоследствии без сбоев.(Проверено на Windows 10, Boost 1.60.0, Visual Studio 2015)

#include <boost/interprocess/sync/interprocess_semaphore.hpp>
#include <boost/interprocess/managed_windows_shared_memory.hpp>

using namespace boost::interprocess;
typedef managed_windows_shared_memory   smem_t;
typedef interprocess_mutex              mutex_t;
typedef interprocess_semaphore          sema_t;

void first_process(smem_t *shm);
void second_process(smem_t *shm);

int main()
{
    smem_t *shm = nullptr;

    try {
        // launching this program for the first time
        // successfully creates a shared memory region
        shm = new smem_t{ create_only, "shm", 1024 };
        first_process(shm);
    } catch (interprocess_exception& e) {
        // launching this program again, it fails to create shared memory
        // since it already exists
        second_process(shm);
    }

    return EXIT_SUCCESS;
}

void first_process(smem_t *shm)
{
    mutex_t *mtx = shm->find_or_construct<mutex_t>("gMutex")();
    sema_t *sema1 = shm->find_or_construct<sema_t>("gSema1")(0);
    sema_t *sema2 = shm->find_or_construct<sema_t>("gSema2")(0);

    sema1->wait();          // wait until the second process locks the mutex
    shm->destroy_ptr(mtx);  // destroy the mutex, doesn't crash (delete mtx crashes)
    sema2->post();          // signal the second process to unlock the mutex
}

void second_process(smem_t *shm)
{
    try {
        shm = new smem_t{ open_only, "shm" };
    } catch (std::exception& e) {
        exit(EXIT_FAILURE);
    }

    mutex_t *mtx = shm->find_or_construct<mutex_t>("gMutex")();
    sema_t *sema1 = shm->find_or_construct<sema_t>("gSema1")(0);
    sema_t *sema2 = shm->find_or_construct<sema_t>("gSema2")(0);

    mtx->lock();
    sema1->post();  // signal the first process that the mutex is locked
    sema2->wait();  // wait until the first process calls destroy_ptr
    mtx->unlock();  // doesn't crash
}
0 голосов
/ 12 июня 2018

Из документации:

Оба процесса совместно используют один и тот же объект

(выделено в оригинале).

Очевидно, что вы не можете уничтожить объект, в то время как другой код может по-прежнему обращаться к нему, даже если это код в другом процессе, потому что оба процесса совместно используют один и тот же объект .

Обратите внимание на ситуацию с общей памятьюуказатель другой.Общая память объект не распределяется между процессами.Область памяти, которой он управляет, есть, но сам объект C ++ является частным для процесса.

Мьютекс, с другой стороны, живет в этой области совместно используемой памяти и поэтому является общей.

Если вы не хотите повторно использовать память, занятую мьютексом, вам вообще не нужно delete _mtx, поэтому не беспокойтесь об общих указателях или счетчиках ссылок.При удалении объекта общей памяти будет просто отменено отображение всего внутри соответствующего сегмента памяти, как будто его там никогда не было.

...