2012-05-10 22 views
1

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

我已经成功实现了第一部分 - 通过遵循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

考虑使用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构造函数中获取锁之后,除了防止其他进程从编写之外,代码正在阻止其他进程从创建 a 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()方法,如果有的话,在“的话费就写到这里 “代码抛出异常,则堆栈将放开,导致:

    • my_exclusive_lock释放独占锁,允许其他进程获取可升级锁。
    • m_lock不具有手柄的互斥,如m_lock.mutex()设为null当所有权在move转移到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
+0

谢谢 - 非常全面,非常有帮助。奇怪的是,我今天早上阅读了右值引用,并意识到move()会比swap()更好,所以我实现了这个。由于偶然事件,读写器类只能使用POD类型,因此写操作是异常安全的。 – bythescruff