Tagged: C++ Toggle Comment Threads | Keyboard Shortcuts

  • wangxinxi 18:59 on January 18, 2014 Permalink | Reply
    Tags: C++   

    Thread-safe map for C++ 

    #ifndef CONCURRENT_MAP
    #define CONCURRENT_MAP
    
    #include <boost/thread.hpp>
    #include <map>
    
    template<typename Key, typename Value>
    class ConcurrentMap
    {
        typedef boost::shared_lock shared_lock;
        typedef boost::shared_mutex shared_mutex;
        
    public:
        ConcurrentMap();
        bool has(Key k) const
        {
            shared_lock<shared_mutex> lock(schemaAccess);
            return m.find(k) == m.end();
        }
        
        void erase(Key k)
        {
            upgrade_lock<shared_mutex> schemaLock(schemaAccess);
            upgrade_to_unique_lock<shared_mutex> schemaUniqueLock(schemaLock);
    
            valueAccess.erase(k);
            m.erase(k);
        }
        
    
        void set(Key k, Value v)
        {
            shared_lock<shared_mutex> lock(schemaAccess);
    
            // set k, v
            if(m.find(k) == m.end()) {
    
                upgrade_lock<shared_mutex> valueLock(*valueAccess[k]);
                upgrade_to_unique_lock<shared_mutex> valueUniqueLock(valueLock);
                
                m.at(k) = v;
                
            }
            // insert k, v
            else {
                upgrade_lock<shared_mutex> schemaLock(schemaAccess);
                lock.unlock();
                upgrade_to_unique_lock<shared_mutex> schemaUniqueLock(schemaLock);
                
                valueAccess.insert(k, new shared_mutext());
                m.insert(std::pair(k, v));
            }
        }
        
    
        Value get(Key k) const
        {
            shared_lock<shared_mutex> lock(schemaAccess);
            return m.at(k);
        }
    
    
        void insert(Key k, Value v)
        {
            upgrade_lock<shared_mutex> schemaLock(schemaAccess);
            upgrade_to_unique_lock<shared_mutex> schemaUniqueLock(schemaLock);
            
            valueAccess.insert(k, new shared_mutext());
            m.insert(std::pair(k, v));
        }
    
    
    private:
        std::map m;
    
        std::map<Key, std::shared_ptr<shared_mutex> > valueAccess;
        shared_mutex schemaAccess;
    }
    
    
    #endif
    
    
    Advertisements
     
    • Maurice Smulders 16:14 on October 7, 2015 Permalink | Reply

      Xinxi,

      Thanks for the example, but as posted, it doesn’t compile… I did make it compile, except i need one more function, and the compiler is driving me nuts. The error message doesn’t make sense….

      Here is the modified class (+ my new function)

      #ifndef CONCURRENTMAP_H_
      #define CONCURRENTMAP_H_

      #include
      #include
      #include

      namespace util
      {
      template
      class ConcurrentMap
      {
      typedef boost::shared_ptr MtxPtr;
      typedef Value(*mutate_func)(Value);

      public:
      ConcurrentMap();
      bool has(Key k) const
      {
      boost::shared_lock lock(schemaAccess);
      return m.find(k) == m.end();
      }

      void erase(Key k)
      {
      boost::upgrade_lock schemaLock(schemaAccess);
      boost::upgrade_to_unique_lock schemaUniqueLock(schemaLock);

      valueAccess.erase(k);
      m.erase(k);
      }

      void set(Key k, Value v)
      {
      boost::shared_lock lock(schemaAccess);

      // set k, v
      if(m.find(k) == m.end())
      {

      boost::upgrade_lock valueLock(*valueAccess[k]);
      boost::upgrade_to_unique_lock valueUniqueLock(valueLock);

      m.at(k) = v;

      }
      // insert k, v
      else
      {
      boost::upgrade_lock schemaLock(schemaAccess);
      lock.unlock();
      boost::upgrade_to_unique_lock schemaUniqueLock(schemaLock);

      valueAccess.insert(k, MtxPtr(new boost::shared_mutex()));
      m.insert(std::pair(k,v));
      }
      }

      /*
      * mutate()
      *
      * IN: key to find record
      * default value if record doesn’t exist
      * mutate function to change old to new if exist
      */

      void mutate(Key k, Value v, mutate_func mf)
      {
      boost::shared_lock lock(schemaAccess);

      // set k, v
      if(m.find(k) == m.end())
      {
      boost::upgrade_lock valueLock(*valueAccess[k]);
      boost::upgrade_to_unique_lock valueUniqueLock(valueLock);
      // if found, pass the current value into the mutate function
      m.at(k) = mf(m.at(k));
      }
      // insert k, v
      else
      {
      boost::upgrade_lock schemaLock(schemaAccess);
      lock.unlock();
      boost::upgrade_to_unique_lock schemaUniqueLock(schemaLock);

      valueAccess.insert(k, MtxPtr(new boost::shared_mutex()));
      m.insert(std::pair(k,v));
      }
      }

      Value get(Key k) const
      {
      boost::shared_lock lock(schemaAccess);
      return m.at(k);
      }

      void insert(Key k, Value v)
      {
      boost::upgrade_lock schemaLock(schemaAccess);
      boost::upgrade_to_unique_lock schemaUniqueLock(schemaLock);

      valueAccess.insert(k, MtxPtr(new boost::shared_mutex()));
      m.insert(std::pair(k, v));
      }

      private:
      std::map m;

      std::map valueAccess;
      boost::shared_mutex schemaAccess;
      };

      } /* namespace util */

      #endif /* CONCURRENTMAP_H_ */

      • Maurice Smulders 16:16 on October 7, 2015 Permalink | Reply

        The function which doesn’t compile is mutate – using GCC 4.8

        ../src/ConcurrentMap.h: In instantiation of ‘void util::ConcurrentMap::mutate(Key, Value, util::ConcurrentMap::mutate_func) [with Key = std::basic_string; Value = long unsigned int; util::ConcurrentMap::mutate_func = long unsigned int (*)(long unsigned int)]’:
        xxx,.cpp:343:37: required from here
        ../src/ConcurrentMap.h:99:13: error: no matching function for call to ‘std::map<std::basic_string, boost::shared_ptr, std::less<std::basic_string >, std::allocator<std::pair<const std::basic_string, boost::shared_ptr > > >::insert(std::basic_string&, util::ConcurrentMap<std::basic_string, long unsigned int>::MtxPtr)’
        valueAccess.insert(k, MtxPtr(new boost::shared_mutex()));

        And the insert is totally the same as the set() call…

    • mauricesmulders 00:58 on October 9, 2015 Permalink | Reply

      There are a few issues in this code as posted. I moved it to use Boost shared_ptr (more portable) and fixed the compilation and deadlock issues.

      #include <boost/thread.hpp>
      #include <boost/shared_ptr.hpp>
      #include <boost/make_shared.hpp>
      #include <map>
      #include "Log.h"
      
      namespace util
      {
      template<typename Key, typename Value>
      class ConcurrentMap
      {
          typedef Value(*mutate_func)(Value);
      
      public:
          ConcurrentMap() {};
          bool has(Key k) const
          {
              boost::shared_lock<boost::shared_mutex> lock(schemaAccess);
              return m.find(k) == m.end();
          }
      
          void erase(Key k)
          {
              boost::upgrade_lock<boost::shared_mutex> schemaLock(schemaAccess);
              boost::upgrade_to_unique_lock<boost::shared_mutex> schemaUniqueLock(schemaLock);
      
              valueAccess.erase(k);
              m.erase(k);
          }
      
      
          void set(Key k, Value v)
          {
              boost::shared_lock<boost::shared_mutex> lock(schemaAccess);
      
              // set k, v
              if(m.find(k) != m.end())
              {
      
                  boost::upgrade_lock<boost::shared_mutex> valueLock(*valueAccess[k]);
                  boost::upgrade_to_unique_lock<boost::shared_mutex> valueUniqueLock(valueLock);
      
                  m.at(k) = v;
              }
              // insert k, v
              else
              {
                  lock.unlock();
                  boost::upgrade_lock<boost::shared_mutex> schemaLock(schemaAccess);
                  boost::upgrade_to_unique_lock<boost::shared_mutex> schemaUniqueLock(schemaLock);
      
                  boost::shared_ptr<boost::shared_mutex> mtx = boost::make_shared<boost::shared_mutex>();
                  valueAccess.insert(std::pair<Key, boost::shared_ptr<boost::shared_mutex> >(k, mtx));
                  m.insert(std::pair<Key,Value>(k,v));
              }
          }
      
          /*
           * mutate()
           *
           * IN: key to find record
           *     default value if record doesn't exist
           *     mutate function to change old to new if exist
           *
           * OUT: N/A
           *
           * This method looks for the map record to determine whether it exists
           * if it does, it calls the mutate_func with the value as a parameter
           * and takes it's return as the new value.
           * If it doesn't, then the value is initialized to v.
           */
          void mutate(Key k, Value v, mutate_func mf)
          {
              boost::shared_lock<boost::shared_mutex> lock(schemaAccess);
      
              // set k, v
              // TODO: Use an iterator. Changes 3 lookups into 1
              if(m.find(k) != m.end())
              {
                  boost::upgrade_lock<boost::shared_mutex> valueLock(*valueAccess[k]);
                  boost::upgrade_to_unique_lock<boost::shared_mutex> valueUniqueLock(valueLock);
                  // if found, pass the current value into the mutate function
                  m.at(k) = mf(m.at(k));
              }
              // insert k, v
              else
              {
                  lock.unlock();
                  boost::upgrade_lock<boost::shared_mutex> schemaLock(schemaAccess);
                  boost::upgrade_to_unique_lock<boost::shared_mutex> schemaUniqueLock(schemaLock);
      
                  boost::shared_ptr<boost::shared_mutex> mtx = boost::make_shared<boost::shared_mutex>();
                  valueAccess.insert(std::pair<Key, boost::shared_ptr<boost::shared_mutex> >(k, mtx));
                  m.insert(std::pair<Key,Value>(k,v));
              }
          }
      
          Value get(Key k) const
          {
              boost::shared_lock<boost::shared_mutex> lock(schemaAccess);
              return m.at(k);
          }
      
      
          void insert(Key k, Value v)
          {
              boost::upgrade_lock<boost::shared_mutex> schemaLock(schemaAccess);
              boost::upgrade_to_unique_lock<boost::shared_mutex> schemaUniqueLock(schemaLock);
      
              boost::shared_ptr<boost::shared_mutex> mtx = boost::make_shared<boost::shared_mutex>();
              valueAccess.insert(std::pair<Key, boost::shared_ptr<boost::shared_mutex> >(k, mtx));
              m.insert(std::pair<Key,Value>(k, v));
          }
      
          /*
           * Iterators are thread unsafe. (and access the internal map..)
           * I'm not even locking the map at this time...
           * Also, only the const iterator is provided for that reason.
           */
           typename std::map<Key,Value>::const_iterator unsafe_begin()
           {
          	 return m.begin();
           }
      
           typename std::map<Key,Value>::const_iterator unsafe_end()
           {
          	 return m.end();
           }
      
      private:
          std::map<Key, Value> m;
      
          std::map<Key, boost::shared_ptr<boost::shared_mutex> > valueAccess;
          boost::shared_mutex schemaAccess;
      };
      
    • wangxinxi 03:01 on October 9, 2015 Permalink | Reply

      Thank you!

  • wangxinxi 19:33 on March 23, 2011 Permalink | Reply
    Tags: C++,   

    用C++做Graphical Model,结果发现我还需要自己写矩阵的inv和det函数。

     
  • wangxinxi 15:58 on March 22, 2011 Permalink | Reply
    Tags: C++, template   

    多年之后才知道,原来自己不懂template

     
    • 冰怨 16:02 on March 22, 2011 Permalink | Reply

      详细地说说吧,我也学习学习

      • wangxinxi 16:09 on March 22, 2011 Permalink | Reply

        最近在做一个项目,想用C++ boost MPL写程序,感觉用起来很不顺手啊。

    • hex 16:52 on March 22, 2011 Permalink | Reply

      您这是微博还是blog。。。

c
Compose new post
j
Next post/Next comment
k
Previous post/Previous comment
r
Reply
e
Edit
o
Show/Hide comments
t
Go to top
l
Go to login
h
Show/Hide help
shift + esc
Cancel