â
Boostã«ä»¥åããread-writeããã¯ã¯å®è£ ããã¦ããããã§ãããã°ããã£ãã¨ãã§æè¿ã®ç©ã§ã¯upgrade_lock, upgrade_to_unique_lockã«ããå¤ãã£ã¦ãã¾ãã
ãã ã®ããã¯ã¨æ¯ã¹ã¦ããã©ã¼ãã³ã¹ãåºãããä¸ã«ç´ æ§ã®è¯ãè¨è¨ã ã¨æãã®ã§ç´¹ä»ãã¦ã¿ããã¨æãã¾ãã
read lock
read-lockãããå ´åã¯shared_mutexãå¼æ°ã«shared_lock
#include <boost/thread.hpp> using namespace boost; shared_mutex mutex; void reader(){ shared_lock<shared_mutex> read_lock(mutex); // ããã§ããã¯ï¼ // ã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ }
ã¹ã³ã¼ããå¤ããã¨åæã«shared_lockã®ãã¹ãã©ã¯ã¿ã§ã¢ã³ããã¯ããã¾ãã
write lock
write-lockããå ´åã¯shared_mutexã«å¯¾ã㦠upgrade_lock â upgrade_to_unique_lockã®é ã§åå¾ãã¦ããå¿ è¦ãããã¾ã
#include <boost/thread.hpp> using namespace boost; shared_mutex mutex; void writer(){ upgrade_lock<shared_mutex> up_lock(mutex); upgrade_to_unique_lock write_lock(up_lock); // ããã§ããã¯ï¼ // ã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ }
upgrade_lockã¨ããã®ã¯ãåæã«ä¸ã¤ããåããªãç¹å¥ãªread lockãã¨èããäºãã§ãã¾ãã
read lockãæ¢ã«åããã¦ãããã©ããã«é¢ãããupgrade_lockã¯ãã ä¸ã¤ã®ã¹ã¬ããã ããä¿æå¯è½ã§ããããã«ããwriterå士ã®è¡çªãã¤ã³ããreaderã¨ã¯å¥ã®æ®µéã§è§£æ±ºããäºãã§ããread lockâwrite lockã®éåããªãææ ¼ãå¯è½ã¨ãªãã¾ãã*1
åæã«ä¸ã¤ã®ã¹ã¬ããããããåããªãread lockã§ããããã®ä»ã®shared_lockãæä»ããäºç¡ãreaderãéªéãã¾ããã
ä½ã®ããã«ããã®ãã¨ããã¨
#include <boost/thread.hpp> using namespace boost; shared_mutex mutex; void hoge(){ upgrade_lock<shared_mutex> up_lock(mutex); // æ¸ãæããå¿ è¦ããããã©ãã調ã¹ã if(/* æ¸ãæããå¿ è¦ããããªã */){ upgrade_to_unique_lock write_lock(up_lock); // ããã§ããã¯ï¼ // readerãå ¨ã¦è¿½ãåºããå¾ã®writeå¦ç }else { // ãã£ã¡ã®å¦çã¯readerãæä»ããã«è¡ãã } }
ã®ããã«æ¸ãäºã§read_lockã¨å ±åå¯è½ãªå©ç¹ãçããã¹ã«ã¼ãããã®åä¸ãæå¾ ã§ãã¾ãã
ããæç§æ¸çãªread writeããã¯ãç¨ãã¦åæ§ã®ç®çãéæãããªã
shared_mutex mutex; void hoge(){ read_lock rlock(mutex); // read lockãç²å¾ // æ¸ãæããå¿ è¦ããããã©ãã調ã¹ã if(/* æ¸ãæããå¿ è¦ããããªã */){ rlock.unlock(); // ãããããã¯ãé¿ããããã«read lockãéæ¾ããå¿ è¦ããã write_lock wlock(mutex); // write lockãç²å¾ // æ¸ãæããå¿ è¦ããããã©ãã調ã¹ã(2度ç®! if(/* æ¸ãæããå¿ è¦ããããªã */){ // ãã£ã¨æ¬å½ã®å¦ç } } }
ãã®ããã«read lockã¨write lock確ä¿å¾ã«ãããããã§ãã¯ããæ¸ãæ¹ã«ãªãã¾ããæ¸ãæããå¿
è¦æ§ããã§ãã¯ããå¦çãéãå ´åã«ã¯ããã©ã¼ãã³ã¹ä½ä¸ãæãã¾ãã
2度ãã§ãã¯ããã®ãé¿ããã«ã¯ãæ¸ãæããå¿
è¦ã®ç¡ãã¨ãã«ãreaderãå
¨ã¦ææ¥ããwrite lockãç²å¾ããããããã¾ãã*2
upgrade_lockéã®é¢ä¿ã¯ããããããããã®ã§
https://gist.github.com/22c650c292e94631bb84
ãã®ãããªã³ã¼ããæ¸ãã¦åä½ã試ãã¦ã¿ãã¨è¯ãããç¥ãã¾ããã
ãç¢å°å
ã®ããã¯ã確ä¿ããã¦ããç¶æ
ã§ç¢å°å
ã®ããã¯ãæ°è¦ã«ç¢ºä¿ã§ãããããå³ã«è¡¨ãã¨ãããªæãã§ãã
*1:æ®éã®read writeããã¯ãéåãç¡ãææ ¼å¯è½ã«ããã¨ãè¤æ°ã®readerãææ ¼ããæã«ãäºãã®read lockãéæ¾å¾ ã¡ããäºã«ãªããããããããã¯ãã¾ã
*2:ãã以å¤ã§ã¯ãããããã¯ããå ´åã®äº¤æ¸å¦çãä»ããææ ¼å¯è½ããã¯ã«ãããããããç¡ããããªâ¦
å®ç¨ä¾
ãã¹ã¬ããéã§å
±æããå¤æ°ã®ã¢ã¯ã»ã¹æ¨©å¶å¾¡ã C++ ã³ã³ãã¤ã©ã§å¼·å¶ããæ¹æ³ã
http://developer.cybozu.co.jp/kazuho/2009/06/c-c79a.html
ãupgrade_lockãå©ç¨ãã¦å®è£
ãã¦ã¿ã¾ãã
ããã¯mutexã¨ä¿è·å¯¾è±¡ãªãã¸ã§ã¯ããå¯çµåããããªãã¸ã§ã¯ããä½ãäºã§ãããã¯ç¡ãã§ã¢ã¯ã»ã¹ããå±éºãªã³ã¼ããç¦æ¢ãããã¨ãç®çã¨ãã¦ãã¾ããread lockã確ä¿ããå ´åã«ã¯constã§ããå¤ãåããªããããã£ããæ¸ãæããå¿é
ãããã¾ããã
ããã
// rwsync.hpp #include <boost/thread.hpp> #include <boost/noncopyable.hpp> template <typename T> class rwsync : boost::noncopyable{ T m_obj; typedef boost::shared_mutex smutex; smutex lock; friend class read_ref; friend class upgrade_ref; friend class write_ref; public: class read_ref : public boost::noncopyable{ // read lock boost::shared_lock<smutex> m_lock; const rwsync<T>* const m_ref; public: read_ref(rwsync& mutex):m_lock(mutex.lock),m_ref(&mutex){} const T& operator*() const { return m_ref->m_obj; } const T* operator->() const { return &operator*(); } }; class write_ref; class upgrade_ref : public boost::noncopyable{ // upgrade lock friend class write_ref; boost::upgrade_lock<smutex> m_lock; rwsync<T>* const m_ref; public: upgrade_ref(rwsync& mutex):m_lock(mutex.lock),m_ref(&mutex){} const T& operator*() const { return m_ref->m_obj; } const T* operator->() const { return &operator*(); } }; class write_ref : public boost::noncopyable{ // unique lock boost::upgrade_to_unique_lock<smutex> m_lock; rwsync<T>* const m_ref; public: write_ref(upgrade_ref& lock):m_lock(lock.m_lock),m_ref(lock.m_ref){} T& operator*() { return m_ref->m_obj; } T* operator->() { return &operator*(); } const T& operator*() const { return m_ref->m_obj; } const T* operator->() const { return &operator*(); } }; };
ãã®ãããªããããç¨æãã¦ãããã¨ã§
// 使ç¨ä¾ #include "rwsync.hpp" rwsync<std::vector<int> > sync_vector; // 宣è¨ã¯ãããªã«ç°¡åï¼ bool reader(){ rwsync<std::vector<int> >::read_ref vector_ref(sync_vector); // ãã®ããã«ããã¯ãåã£ããªãã¸ã§ã¯ãçµç±ã§ããã¢ã¯ã»ã¹ã§ããªã for(std::vector<int>::const_iterator iter = vector_ref->begin(); iter != vector_ref->end(); ++iter){ // ä½ãå¦ç } } bool writer(){ rwsync<std::vector<int> >::upgrade_ref vector_up_ref(sync_vector); if(vector_up_ref->front == 10){ // é åã®å é ã10ãªã rwsync<std::vector<int> >::write_ref vector_ref(vector_up_ref); vector_ref->push_back(20); } }
ã®ããã«æ¸ãã¾ã
rwsyncããä½ããã®refãéããªãéãããã¯ããã¦ãããªãã¸ã§ã¯ãã«ã¯è§¦ãããã¾ããã
ã¾ããread_refãupgrade_refããã¯constä»ãã®ãã¤ã³ã¿/åç
§ããå¾ãããªããããªãã¸ã§ã¯ãã«ä¸ç¨æã«è§¦ãããã«ãªã£ããã³ã³ãã¤ã©ãã¨ã©ã¼ãåãã¦ããã¾ãã
ããã使ã£ã¦ããã·ã¥ããããä¿è·ãã¦ã¿ãä¾ã以ä¸ã«ç¶ãã¾ãã
unordered_mapã§memcached風ã®ã»ãã³ãã£ã¯ã¹ãå®è£
ãã¾ãã