当其他进程可能正在使用它时删除boost interprocess_mutex

时间:2018-06-05 02:30:34

标签: c++ boost boost-interprocess

我尝试将interprocess_mutexmanaged_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()是否安全。在interprocess_mutex boost::interprocess::shared_ptr中,没有提到它是否仍然被破坏,即使其他进程有对象引用它。

我已经搜索了doc,我猜测我的选择是在这种情况下使用DPI-1050: Oracle Client library must be at version 11.2 or higher。我在这儿吗?这是我应该采取的选择吗?

2 个答案:

答案 0 :(得分:3)

来自文档:

  

两个进程共享同一个对象

(强调原文)。

显然你不能销毁一个对象,而其他一些代码仍然可以访问它,即使它是另一个进程中的代码,因为两个进程共享同一个对象

请注意共享内存指针的情况不同。进程之间不共享共享内存对象。它管理的内存区域是,但C ++对象本身对进程是私有的。

另一方面,互斥锁存在于共享内存区域的中,因此是共享的。

除非您想重用互斥锁占用的内存,否则根本不需要delete _mtx,所以不要为共享指针或引用计数器而烦恼。删除共享内存对象只会取消映射相应内存段内的所有内容,就像它从未存在一样。

答案 1 :(得分:0)

首先,指向共享存储器上分配的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
}