shared_ptr實現多執行緒讀寫copy-on-write

liiinuuux發表於2016-09-26
利用boost的shared_ptr可以實現“讀不阻塞寫”。過程中每次讀取不需要複製資料,而只需要在要寫的時候複製一份資料:

點選(此處)摺疊或開啟
  1. #include <iostream>
  2. #include <cstdlib>
  3. #include <map>
  4. #include <vector>
  5. #include <boost/smart_ptr.hpp>
  6. #include <boost/make_shared.hpp>
  7. #include <boost/enable_shared_from_this.hpp>
  8. #include <boost/bind.hpp>
  9. #include <boost/function.hpp>
  10. #include <boost/noncopyable.hpp>

  11. #include <pthread.h>
  12. #include <unistd.h>

  13. using namespace std;


  14. class mutex_lock: public boost::noncopyable
  15. {
  16. public:
  17.     mutex_lock(){pthread_mutex_init(&_mutex, NULL);}
  18.     ~mutex_lock(){pthread_mutex_destroy(&_mutex);}
  19.     void lock() {pthread_mutex_lock(&_mutex);}
  20.     void unlock() {pthread_mutex_unlock(&_mutex);}
  21. private:
  22.     pthread_mutex_t _mutex;
  23. };

  24. class mutex_locker: public boost::noncopyable
  25. {
  26. public:
  27.     explicit mutex_locker(mutex_lock& lk): _lk(lk){_lk.lock();}
  28.     ~mutex_locker(){_lk.unlock();}
  29. private:
  30.     mutex_lock& _lk;
  31. };


  32. // 負責都和寫的物件
  33. class rwobj
  34. {
  35. public:
  36.     rwobj(){sp_data = boost::make_shared<vector<int> >();}
  37.     void read_data()
  38.     {
  39.         boost::shared_ptr<vector<int> > sp;
  40.         {
  41.             cout << "--------------------- read wait" << endl;
  42.             mutex_locker lk(l); // 臨界區足夠小,適合用mutex。
  43.             sp = sp_data; // 利用區域性的shared_ptr來增加資料的引用計數,告訴寫執行緒不要修改這份資料
  44.             cout << "read sleep 1" << endl;
  45.             sleep(1); // 為了阻塞其它執行緒
  46.         }

  47.         cout << "read size " << sp->size() << endl;
  48.         cout << "read sleep 2" << endl;
  49.         sleep(2);
  50.     }

  51.     void write_data(int i)
  52.     {
  53.         {
  54.             cout << "------------------------------ write wait" << endl;
  55.             mutex_locker lk(l); // 寫執行緒的臨界區比較大
  56.             if(!sp_data.unique())
  57.             {
  58.                 // 如果sp_data引用計數大於1,說明有其他執行緒在讀(透過read_data()提升了引用計數)。
  59.                 // 此時將資料複製一份,再利用reset或者swap讓sp_data指向新資料,老資料讓讀執行緒繼續讀。
  60.                 // 這個寫執行緒現在獨佔了sp_data,而之前那份資料在所有讀執行緒讀完之後,引用計數會變成0,被最後一個讀執行緒自動析構。
  61.                 sp_data.reset(new vector<int>(*sp_data));
  62.                 cout << "-------------------------------- copy on write" << endl;
  63.             }
  64.             sp_data->push_back(i);
  65.         }
  66.         cout << "sleep write" << endl;
  67.         sleep(1);
  68.     }
  69. private:
  70.     boost::shared_ptr<vector<int> > sp_data;
  71.     mutex_lock l;
  72. };


  73. rwobj obj;

  74. // 讀執行緒
  75. void* read_thread(void* arg)
  76. {
  77.     while(1)
  78.     {
  79.         obj.read_data();
  80.     }
  81. }

  82. 寫執行緒
  83. void* write_thread(void* arg)
  84. {
  85.     int i = 1;
  86.     while(1)
  87.     {
  88.         obj.write_data(i++);
  89.     }
  90. }

  91. int main()
  92. {
  93.     pthread_t thread1,thread2, thread3;
  94.     pthread_create(&thread1, NULL, &read_thread, NULL );
  95.     pthread_create(&thread2, NULL, &read_thread, NULL );
  96.     pthread_create(&thread3, NULL, &write_thread, NULL );
  97.     pthread_join(thread1,NULL);
  98.     pthread_join(thread2,NULL);
  99.     pthread_join(thread3,NULL);
  100.     return 0;
  101. }





來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26239116/viewspace-2125592/,如需轉載,請註明出處,否則將追究法律責任。

相關文章