【问题标题】:How to hold a Boost upgradable_lock for the lifetime of an object?如何在对象的生命周期内持有 Boost upgradable_lock?
【发布时间】:2012-05-19 04:58:21
【问题描述】:

我正在实现一对用于进程间通信的类,其中一个进程将是唯一的写入者,并且会有很多读取者。一类处理阅读;一个处理写作。为了防止任何其他进程成为编写器,我想要编写器类的单个对象,该对象在其整个生命周期内保持对 boost::named_upgradable_mutex 的可升级锁定。为此,编写器类有一个boost::interprocess::upgradable_lock 类型的成员变量,在构造对象时将其传递给互斥锁。当写入器进程写入时,它会调用写入器类的 Write() 方法,该方法应该将该锁升级为独占,执行写入,并自动将独占锁降级为仅可再次升级。

按照Lock Transfers Through Move Semantics 上的 Boost 文档,我已经设法在我的 writer 类的 Write() 方法中实现了第一部分 - 将锁升级为独占。但是,第二部分 - 将锁降级为可升级 - 导致类型为 boost::interprocess::upgradable_lock 的新局部变量将超出范围并在 Write() 返回时释放互斥锁。我需要将该可升级锁放回我的班级的 upgradable_lock 成员变量中,以便升级功能将仅保留在我的 writer 对象中。最好的方法是什么?我唯一能想到的就是在返回之前将局部变量与我的成员变量交换。代码如下所示:

using boost::interprocess;
scoped_lock<named_upgradable_mutex> my_exclusive_lock(move(m_lock));

//  do write here

upgradable_lock<named_upgradable_mutex> my_demoted_lock(move(my_exclusive_lock));
m_lock.swap(my_demoted_lock);  //  how else to do this?

这行得通,但最后一行确实违反直觉,我花了一段时间才想到。有没有更好的办法?是否可以将降级锁直接放入我的成员变量中?另外,重用成员变量来存储降级的锁,会不会产生意想不到的后果?

【问题讨论】:

    标签: c++ boost mutex boost-interprocess


    【解决方案1】:

    考虑使用move assignment operator。以下代码使用swap()

    upgradable_lock<named_upgradable_mutex> my_demoted_lock(move(my_exclusive_lock));
    m_lock.swap(my_demoted_lock);
    

    会变成:

    m_lock = upgradable_lock<named_upgradable_mutex>(move(my_exclusive_lock));
    

    在这种特殊情况下,swap() 和移动赋值运算符可以互换,没有任何副作用,因为 m_lock 处于默认构造状态(m_lock.owns() == falsem_lock.mutex() == 0)。


    我想不出重用可升级锁的成员变量的任何意外后果。但是,有几个主题需要考虑:

    • 一个目标是“防止任何其他进程成为作家”。在Writer 构造函数中获取锁后,代码会阻止其他进程创建Writer,同时阻止其他进程写入。结果,阻塞调用可能对应用程序代码强加或不方便。考虑以下代码:

      Reader reader;
      Writer writer; // This may block, but the application code cannot react
                     // to it without dedicating an entire thread to the
                     // construction of the writer.
      

      一种折衷的替代方法可能是尝试通过this constructor 获取锁,然后将成员函数添加到Writer 以提供应用程序更多的控制权。虽然这仍然允许其他进程创建Writer,但它会阻止多个进程拥有写入权限:

      class Writer
      {
      public:
        bool IsPrivileged();         // Returns true if this the privileged Writer.
        bool TryBecomePrivileged();  // Non-blocking attempt to become the
                                     // privileged Writer.  Returns true on success.
        bool BecomePrivileged();     // Blocks waiting to become the privileged
                                     // Writer.  Returns true on success.
        void RelinquishPrivileges(); // We're not worthy...we're not worthy...
      
        enum Status { SUCCESS, NOT_PRIVILEGED };
        Status Write( const std::string& ); // If this is not the privileged Writer,
                                            // then attempt to become it.  If the
                                            // attempt fails, then return
                                            // NOT_PRIVILEGED.
      };
      
    • Writer::Write() 方法中,如果“do write here”代码中的任何调用抛出异常,则堆栈将展开,导致:

      • my_exclusive_lock释放独占锁,让其他进程获得可升级锁。
      • m_lock 没有互斥体句柄,因为当所有权转移到 move 中的 my_exclusive_lock 时,m_lock.mutex() 设置为 null
      • 进一步调用Writer::Write() 将尝试写入而不获取排他锁!即使m_lock 有一个互斥体句柄,m_lock.owns() 也将是false,因此转移到my_exclusive_lock 不会尝试锁定。

    这是一个示例程序:

    #include <boost/interprocess/sync/named_upgradable_mutex.hpp>
    #include <boost/interprocess/sync/sharable_lock.hpp>
    #include <boost/interprocess/sync/upgradable_lock.hpp>
    #include <boost/move/move.hpp>
    #include <iostream>
    
    int main()
    {
      namespace bip = boost::interprocess;
      typedef bip::named_upgradable_mutex mutex_t;
    
      struct mutex_remove
      {
        mutex_remove()  { mutex_t::remove( "example" ); }
        ~mutex_remove() { mutex_t::remove( "example" ); }
      } remover;
    
      // Open or create named mutex.
      mutex_t mutex( bip::open_or_create, "example" );
    
      // Acquire upgradable lock.
      bip::upgradable_lock< mutex_t > m_lock( mutex, bip::try_to_lock );
      std::cout << "upgradable lock own:  " << m_lock.owns()
                << " -- mutex: "            << m_lock.mutex() 
                << std::endl;
    
      // Acquire the exclusive lock.
      {
        std::cout << "++ Entering scope ++" << std::endl;
        std::cout << "Transferring ownership via move: Upgradable->Scoped"
                  << std::endl;
        bip::scoped_lock< mutex_t > exclusive_lock( boost::move( m_lock ) );
        std::cout <<   "upgradable lock owns: " << m_lock.owns()
                  << " -- mutex: "              << m_lock.mutex()
                  << "\nexclusive lock owns:  " << exclusive_lock.owns() 
                  << " -- mutex: "              << exclusive_lock.mutex()
                  << std::endl;
    
        // do write here...
    
        // Demote lock from exclusive to just an upgradable.
        std::cout << "Transferring ownership via move: Scoped->Upgradable"
                  << std::endl;
        m_lock = bip::upgradable_lock< mutex_t >( boost::move( exclusive_lock ) );
        std::cout <<   "upgradable lock owns: " << m_lock.owns()
                  << " -- mutex: "              << m_lock.mutex()
                  << "\nexclusive lock owns:  " << exclusive_lock.owns() 
                  << " -- mutex: "              << exclusive_lock.mutex()
                  << std::endl;
        std::cout << "-- Exiting scope --" << std::endl;
      }
      std::cout << "upgradable lock own:  " << m_lock.owns()
                << " -- mutex: "            << m_lock.mutex() 
                << std::endl;
    
      return 0;
    }
    

    产生以下输出:

    可升级锁拥有:1 -- 互斥锁:0xbff9b21c
    ++ 进入范围 ++
    通过 move 转移所有权:Upgradable->Scoped
    可升级锁拥有:0 -- 互斥锁:0
    独占锁拥有:1 -- 互斥锁:0xbff9b21c
    通过移动转移所有权:Scoped->Upgradable
    可升级锁拥有:1 -- 互斥锁:0xbff9b21c
    独占锁拥有:0 -- 互斥锁:0
    -- 退出范围 --
    可升级锁拥有:1 -- 互斥锁:0xbff9b21c

    【讨论】:

    • 谢谢 - 非常全面且非常有帮助。巧合的是,今天早上我正在阅读右值引用,并意识到move() 会比swap() 更好,所以我已经实现了。巧合的是,reader 和 writer 类仅适用于 POD 类型,因此 write 操作是异常安全的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-28
    • 1970-01-01
    • 1970-01-01
    • 2011-03-16
    相关资源
    最近更新 更多