【问题标题】:Example of how to use boost upgradeable mutexes如何使用 boost 可升级互斥锁的示例
【发布时间】:2011-04-23 05:47:45
【问题描述】:

我有一个多线程服务器应用程序,它需要对一些共享内存进行互斥锁。

共享内存基本上是 sTL 映射等。

大部分时间我只是在阅读地图。 但是,我也需要偶尔添加。

例如 typedef std::map MessageMap; 消息映射消息映射; boost: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.
}

编辑: 我可能会混淆不同的锁类型。

共享/升级和独占之间有什么区别。 即我不明白解释。 听起来如果您只想允许大量读者,那么您想要获得的只是共享访问权限。而要写入您的共享内存,您只需要升级访问权限。还是你需要独家? boost 中的解释并不明确。

是否获得了升级访问权限,因为您可能会写。但是共享意味着你肯定不会写是这个意思吗?

编辑:让我更清楚地解释一下我想要做什么。我对答案还不满意。

这里又是一个例子,但我也使用了一些代码的例子。 只是一个说明,不是实际的代码。

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?
    }

【问题讨论】:

    标签: c++ boost-thread boost-interprocess


    【解决方案1】:

    你说你的应用程序是多线程的,所以你应该使用 boost::thread 而不是 boost::interprocess。

    根据文档(未经测试),您应该这样做:

    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..
    

    另请注意,您在锁定读取访问权限时获取了it,因此有人可能会删除此节点,并且当您到达写入部分时它不再有效。错误,抱歉。 p>

    编辑:我认为 explanation in boost 很清楚。无论如何,让我们尝试改写给您:

    互斥锁概念主要分为三种类型(我不计算 TimedLockable,因为它与您的问题无关):

    • 可锁定 — 只是一个简单的独占所有权互斥锁。如果有人锁定()它,没有人可以再次锁定()它,直到所有者解锁()它。 boost::thread::mutex 实现了这个概念。要以 RAII 样式锁定此概念,请使用 lock_guard 或 unique_lock 以获得更复杂的界面。
    • SharedLockable — 是具有额外“共享”所有权的 Lockable。您可以使用 lock() 获得独占所有权或使用 lock_shared() 获得共享所有权。如果您锁定共享部分,您无法将您的所有权升级为独占部分。您需要再次 unlock_shared() 和 lock(),这意味着其他人可能会在 unlock_shared() 和 lock() 之间修改受保护的资源。当您先验地知道您将对资源进行何种访问时,它会很有用。 shared_mutex 实现了这个概念。使用 lock_guard 或 unique_lock 获取独占所有权,使用 shared_lock 获取共享所有权。
    • UpgradeLockable — 是 SharedLockable,它允许您从共享所有权升级到独占所有权而无需解锁。 shared_mutex 也实现了这个概念。您可以使用上述锁来获得独占或共享所有权。要获得可升级的共享所有权,请使用 upgrade_lock 并使用 upgrade_to_unique_lock 进行升级。

    【讨论】:

    • 对不起,我想也许我想使用 boost::upgrade_lock 和 boost::upgrade_to_unique_lock。也许您可以解释它们之间的区别。请参阅我编辑的问题。
    • 使用 UpgradeLockable 只能有一个线程处于该状态,但有几个线程可以处于 SharedLockable 是正确的吗?所以为了让升级锁成为唯一锁,所有共享锁都需要正确解锁?
    • @Matt:“那里有 UpgradeLockable ...”只有一个处于独特状态,许多处于可升级或共享状态。 “所以为了升级......”是的。
    • 所以基本上,这是NOT OP 问题的答案。因为一个可升级锁不能被多个线程获取(即使它还没有升级)...
    • 在某些文档中遇到了“升级互斥类型”一词,在任何地方都找不到官方定义;感谢您出色而清晰的解释。
    【解决方案2】:

    如果您只使用单个进程,则不需要boost-interprocess。正如库名称所暗示的那样,它用于进程间通信 (IPC)。您很可能希望使用 boost-thread mutex 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
        }
    }
    

    boost 邮件列表中的 post 也解释了这一点。

    【讨论】:

    • 编辑:谢谢山姆。你能看看我在问题底部编辑的上面的例子吗?那是正确的用法吗?
    • @Matt,在您的情况下,由于在输入 threadoolthread 时无条件获取读锁,我认为您想使用 ybungalobill 具有 describedboost::upgrade_to_unique_lock。不过,我从未使用过boost::adopt_lock_t(),所以我不熟悉这种行为,也许它有效。
    • 不会在线程池函数开头使用upgrade_to_unique_lock 意味着线程池中一次只能运行一个线程?
    • @Matt 是的,这是正确的。这就是为什么你不想这样做。通过仅在您需要的范围内升级读锁来获取独占锁。
    • boost::adopt_lock_t() 导致锁定为assumed locked already,这不是你想要的。
    猜你喜欢
    • 2013-01-01
    • 2022-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-27
    相关资源
    最近更新 更多