2010-10-09 21 views
7

Tôi có một ứng dụng máy chủ đa luồng cần các khóa mutex trên một số bộ nhớ dùng chung.Ví dụ về cách sử dụng các đột biến nâng cấp có thể nâng cấp

Bộ nhớ dùng chung về cơ bản là bản đồ sTL vv.

Phần lớn thời gian tôi chỉ đọc từ bản đồ. Nhưng, tôi cũng cần phải thỉnh thoảng thêm vào nó.

ví dụ: typedef std :: Bản đồ MessageMap; Bản đồ thư MessageMap; tăng: shared_mutex access_;

void ProcessMessage(Message* message) 
{ 
    // Access message... read some stuff from it message->... 

    UUID id = message->GetSessionID(); 

    // Need to obtain a lock here. (shared lock? multiple readers) 
    // How is that done? 
    boost::interprocess::scoped_lock(access_); 

    // Do some readonly stuff with msgmap 
    MessageMap::iterator it = msgmap.find(); 
    // 

    // Do some stuff... 

    // Ok, after all that I decide that I need to add an entry to the map. 
    // how do I upgrade the shared lock that I currently have? 
    boost::interprocess::upgradable_lock 


    // And then later forcibly release the upgrade lock or upgrade and shared lock if I'm not looking 
    // at the map anymore. 
    // I like the idea of using scoped lock in case an exception is thrown, I am sure that 
    // all locks are released. 
} 

EDIT: Tôi có thể gây nhầm lẫn với các loại khóa khác nhau.

Sự khác biệt giữa chia sẻ/nâng cấp và độc quyền. tức là tôi không hiểu giải thích. Có vẻ như bạn chỉ muốn cho phép nhiều người đọc, quyền truy cập được chia sẻ là tất cả những gì bạn muốn có. Và để ghi vào bộ nhớ chia sẻ của bạn, bạn chỉ cần truy cập nâng cấp. Hay bạn cần độc quyền? Lời giải thích trong tăng là bất cứ điều gì nhưng rõ ràng.

Quyền truy cập nâng cấp có được do bạn có thể viết hay không. Nhưng chia sẻ có nghĩa là bạn chắc chắn sẽ không viết là những gì nó có nghĩa là?

EDIT: Hãy để tôi giải thích những gì tôi muốn làm với một chút rõ ràng hơn. Tôi chưa hài lòng với câu trả lời.

Đây là ví dụ trên một lần nữa nhưng với ví dụ về một số mã mà tôi đang sử dụng. Chỉ là minh họa, không phải mã thực.

typedef boost::shared_mutex Mutex; 
typedef boost::shared_lock<Mutex> ReadLock; 
typedef boost::unique_lock<Mutex> WriteLock; 
Mutex mutex; 
typedef map<int, int> MapType; // Your map type may vary, just change the typedef 
MapType mymap; 

void threadoolthread() // There could be 10 of these. 
{ 
    // Add elements to map here 
    int k = 4; // assume we're searching for keys equal to 4 
    int v = 0; // assume we want the value 0 associated with the key of 4 

    ReadLock read(mutex); // Is this correct? 
    MapType::iterator lb = mymap.lower_bound(k); 
    if(lb != mymap.end() && !(mymap.key_comp()(k, lb->first))) 
    { 
     // key already exists 
    } 
    else 
    { 
     // Acquire an upgrade lock yes? How do I upgrade the shared lock that I already  have? 
     // I think then sounds like I need to upgrade the upgrade lock to exclusive is that correct as well? 

     // Assuming I've got the exclusive lock, no other thread in the thread pool will be able to insert. 
     // the key does not exist in the map 
     // add it to the map 
     { 
      WriteLock write(mutex, boost::adopt_lock_t()); // Is this also correct? 
      mymap.insert(lb, MapType::value_type(k, v)); // Use lb as a hint to insert, 
                 // so it can avoid another lookup 
     } 
     // I'm now free to do other things here yes? what kind of lock do I have here, if any? does the readlock still exist? 
    } 

Trả lời

11

Bạn nói rằng ứng dụng của bạn đa luồng, vì vậy bạn nên sử dụng boost :: thread not boost :: interprocess.

Từ các tài liệu (không kiểm tra), bạn nên làm theo cách này:

typedef boost::thread::shared_mutex shared_mutex; 
boost::thread::upgrade_lock<shared_mutex> readLock(access_); 

// Read access... 

boost::thread::upgrade_to_unique_lock<shared_mutex> writeLock(readLock); 

// Write access.. 

Cũng lưu ý rằng bạn có được it khi bạn khóa để truy cập đọc, vì vậy ai đó có thể xóa nút này và nó không còn giá trị khi bạn đến phần viết. WRONG, xin lỗi.

CHỈNH SỬA: Tôi nghĩ rằng explanation khi tăng rõ ràng. Hãy thử nói lại nó cho bạn anyway:

Có ba loại chính của khái niệm mutex (Tôi không đếm TimedLockable vì nó không liên quan đến câu hỏi của bạn):

  • có thể khóa — chỉ là một đơn giản, độc quyền sở hữu mutex. Nếu ai đó khóa() thì không ai có thể khóa() lại cho đến khi chủ sở hữu mở khóa(). boost :: thread :: mutex thực hiện khái niệm này. Để khóa khái niệm này trong phong cách RAII, sử dụng lock_guard hoặc unique_lock cho một giao diện phức tạp hơn.
  • SharedLockable — là khóa có quyền sở hữu "được chia sẻ" bổ sung. Bạn có thể có quyền sở hữu độc quyền với khóa() hoặc quyền sở hữu được chia sẻ với lock_shared().Nếu bạn khóa phần được chia sẻ, bạn không thể nâng cấp quyền sở hữu của bạn lên phiên bản độc quyền. Bạn cần phải unlock_shared() và khóa() một lần nữa có nghĩa là ai đó khác có thể sửa đổi tài nguyên được bảo vệ giữa unlock_shared() và lock(). Nó rất hữu ích khi bạn biết một ưu tiên loại truy cập vào tài nguyên bạn sẽ làm. shared_mutex thực hiện khái niệm này. Sử dụng lock_guard hoặc unique_lock để nhận quyền sở hữu độc quyền và shared_lock để nhận quyền sở hữu được chia sẻ.
  • UpgradeLockable — là SharedLockable cho phép bạn nâng cấp từ quyền sở hữu chia sẻ lên quyền sở hữu độc quyền mà không cần mở khóa. shared_mutex cũng thực hiện khái niệm này. Bạn có thể sử dụng các khóa ở trên để nhận quyền sở hữu độc quyền hoặc chia sẻ. Để có được nâng cấp quyền sở hữu được chia sẻ, hãy sử dụng upgrade_lock và nâng cấp nó bằng upgrade_to_unique_lock.
+0

Xin lỗi tôi nghĩ rằng có lẽ tôi muốn sử dụng boost :: upgrade_lock và boost :: upgrade_to_unique_lock. Có lẽ bạn có thể giải thích sự khác biệt giữa chúng. Xem câu hỏi đã chỉnh sửa của tôi. – Matt

+0

@Matt H: xem câu trả lời đã chỉnh sửa. – ybungalobill

+0

Với UpgradeLockable, có thể chỉ có một luồng trong trạng thái đó nhưng một số có thể trong SharedLockable là đúng? do đó, để khóa nâng cấp trở thành khóa duy nhất, tất cả khóa được chia sẻ cần phải được mở khóa chính xác? – Matt

5

Bạn không muốn boost-interprocess nếu bạn chỉ sử dụng một quy trình. Như tên thư viện ngụ ý, nó được sử dụng cho Inter-Process Communication (IPC). Bạn rất có thể muốn sử dụng boost-threadmutex and locking concepts.

#include <boost/thread/locks.hpp> 
#include <boost/thread/shared_mutex.hpp> 

int 
main() 
{ 
    typedef boost::shared_mutex Mutex; 
    typedef boost::shared_lock<Mutex> ReadLock; 
    typedef boost::unique_lock<Mutex> WriteLock; 
    Mutex mutex; 

    { 
     // acquire read lock 
     ReadLock read(mutex); 

     // do something to read resource 
    } 

    { 
     // acquire write lock 
     WriteLock write(mutex, boost::adopt_lock_t()); 

     // do something to write resource 
    } 
} 

có một số post trong danh sách gửi thư cũng giải thích điều này.

+1

Chỉnh sửa: cảm ơn Sam. Bạn có thể xem ví dụ ở trên mà tôi đã chỉnh sửa ở cuối câu hỏi không. Đó có phải là cách sử dụng đúng không? – Matt

+1

@Matt, trong trường hợp của bạn kể từ khi khóa đọc là vô điều kiện có được khi nhập 'threadoolthread', tôi nghĩ bạn muốn sử dụng' boost :: upgrade_to_unique_lock' mà ybungalobill đã [mô tả] (http://stackoverflow.com/questions/3896717/example-of-how-to-use-boost-upgradeable-mutexes/3896816 # 3896816). Mặc dù, tôi chưa bao giờ sử dụng 'boost :: adopt_lock_t()' vì vậy tôi không quen thuộc với hành vi, có lẽ nó hoạt động. –

+0

sẽ không sử dụng upgrade_to_unique_lock khi bắt đầu chức năng pool thread có nghĩa là chỉ có một luồng trong nhóm luồng có thể chạy cùng một lúc? – Matt