如何在对象的生命周期中持有Boost upgradedable_lock?

时间:2012-05-10 15:14:06

标签: c++ boost mutex boost-interprocess

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

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

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?

这样可行,但最后一行真的违反直觉并且花了我一段时间才想到。有没有更好的办法?是否可以将降级锁直接放入我的成员变量中?此外,是否有重复使用成员变量存储降级锁的意外后果?

1 个答案:

答案 0 :(得分: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无法处理互斥锁,因为m_lock.mutex()在所有权转移到move中的null时设置为my_exclusive_lock
    • 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;
}

产生以下输出:

upgradable lock own:  1 -- mutex: 0xbff9b21c
++ Entering scope ++
Transferring ownership via move: Upgradable->Scoped
upgradable lock owns: 0 -- mutex: 0
exclusive lock owns:  1 -- mutex: 0xbff9b21c
Transferring ownership via move: Scoped->Upgradable
upgradable lock owns: 1 -- mutex: 0xbff9b21c
exclusive lock owns:  0 -- mutex: 0
-- Exiting scope --
upgradable lock own:  1 -- mutex: 0xbff9b21c