2012-05-10 46 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