【问题标题】:Deleting boost interprocess_mutex when other process might be using it当其他进程可能正在使用 boost interprocess_mutex 时删除它
【发布时间】:2018-06-05 02:30:34
【问题描述】:

我正在尝试将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;
}

我可以看到在~A() 中调用delete _shm; 是安全的,因为managed_windows_shared_memory 只有在每个使用它的进程都销毁managed_windows_shared_memory 对象时才会被销毁,如doc 中所写。

但是,我不确定在~A() 中调用delete _mtx; 是否安全。在interprocess_mutexdoc中,并没有提到即使其他进程有对象引用它是否仍然被销毁。

我搜索了this,我猜我的选择是在这种情况下使用boost::interprocess::shared_ptr。我在这里吗?这是我应该采取的选择吗?

【问题讨论】:

  • 这是一个操作系统实现细节,Boost 文档小心避免提及的那种细节。您可以放心地假设操作系统在底层命名互斥内核对象上使用引用计数。只有最后一个正在运行的进程发出的最后一次调用才会将其计数为 0 并将其销毁。你没有问题。
  • 感谢您的评论。然而,就我而言,我使用的是匿名互斥锁,而不是命名互斥锁。 匿名互斥体命名互斥体取自this boost doc。我已经进行了一些测试,似乎删除由其他进程持有的interprocess_mutex 会导致错误。我将发布我的测试代码。如果我错了,请纠正我。
  • 根据boost的说法:如果在调用析构函数后任何进程使用互斥锁,结果是未定义的。我猜如果你有引用计数,你可以在拥有唯一对象时删除,所以使用 shared_ptr 映射到共享内存可能是答案。

标签: c++ boost boost-interprocess


【解决方案1】:

来自文档:

两个进程共享同一个对象

(强调原文)。

很明显,您不能在其他代码仍然可以访问它的情况下销毁一个对象,即使它是另一个进程中的代码,因为两个进程共享同一个对象

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

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

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

【讨论】:

    【解决方案2】:

    首先,指向分配在共享内存上的interprocess_mutex 的指针不能直接用delete 销毁,因为指针指向映射的进程地址空间中的某个地址 em> 到互斥锁实际所在的共享内存区域。因此,在下面的代码中,执行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


    其次,通过编译以下代码并在两个单独的控制台上运行两次,可以检查在其他进程锁定互斥锁时使用destroy_ptr 销毁interprocess_mutex 不会崩溃。此外,持有锁的进程可以在之后安全地解锁互斥锁而不会崩溃。 (在 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
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多