天天看點

diy資料庫(四)--鎖和隊列

一、鎖的概述

1.互斥鎖

      用來保證臨界資源被互斥通路。

2.讀寫鎖

      在一個線程中,當一個讀寫鎖中的讀鎖被申請後,其他線程可以再申請讀鎖,但不能申請寫鎖。

      在一個線程中,當一個讀寫鎖中的寫鎖被申請後,其他線程不能申請讀鎖,也不能申請寫鎖。

3.自旋鎖

      等待條件時,不讓出cpu。nginx中由于每個工作程序要求快速響應使用者,就用到了自選鎖。

4.遞歸鎖

      同一個線程可以對一個遞歸鎖加鎖多次(其他鎖沒有這樣的功能),但必須解鎖同樣多次。

另外,主要通過條件變量和信号量來進行線程間同步。

二、diy資料庫中鎖的實作

#ifndef OSSLATCH_HPP__
#define OSSLATCH_HPP__

#include "core.hpp"


#define oss_mutex_t					pthread_mutex_t
#define oss_mutex_init					pthread_mutex_init
#define oss_mutex_destroy				pthread_mutex_destroy
#define oss_mutex_lock					pthread_mutex_lock
#define oss_mutex_trylock(__lock)	(pthread_mutex_trylock( (__lock) ) == 0 )
#define oss_mutex_unlock				pthread_mutex_unlock

#define oss_rwlock_t					pthread_rwlock_t
#define oss_rwlock_init					pthread_rwlock_init
#define oss_rwlock_destroy				pthread_rwlock_destroy
#define oss_rwlock_rdlock				pthread_rwlock_rdlock
#define oss_rwlock_rdunlock				pthread_rwlock_unlock
#define oss_rwlock_wrlock				pthread_rwlock_wrlock
#define oss_rwlock_wrunlock				pthread_rwlock_unlock
#define oss_rwlock_rdtrylock(__lock)	(pthread_rwlock_tryrdlock( (__lock) ) == 0 )
#define oss_rwlock_wrtrylock(__lock)	(pthread_rwlock_trywrlock ( ( __lock) ) == 0 )

enum OSS_LATCH_MODE
{
   SHARED ,//共享
   EXCLUSIVE//互斥
} ;

class ossXLatch//互斥鎖
{
private :
   oss_mutex_t _lock ;
public :
   ossXLatch ()
   {
      oss_mutex_init ( &_lock, 0 ) ;
   }
   ~ossXLatch ()
   {
		oss_mutex_destroy(&_lock);
   }
   void get ()
   {
		oss_mutex_lock(&_lock);
   }
   void release ()
   {
		oss_mutex_unlock(&_lock);
   }
   bool try_get ()
   {
		return oss_mutex_trylock(&_lock);
   }
} ;

class ossSLatch//共享鎖
{
private :
   oss_rwlock_t _lock ;
public :
   ossSLatch ()
   {
      oss_rwlock_init ( &_lock, 0 ) ;
   }

   ~ossSLatch ()
   {
      oss_rwlock_destroy ( &_lock ) ;
   }

   void get ()//寫鎖
   {
      oss_rwlock_wrlock ( &_lock ) ;
   }

   void release ()
   {
      oss_rwlock_wrunlock ( &_lock ) ;
   }

   bool try_get ()
   {
      return ( oss_rwlock_wrtrylock ( &_lock ) ) ;
   }

   void get_shared ()//讀鎖
   {
      oss_rwlock_rdlock ( &_lock ) ;
   }

   void release_shared ()
   {
      oss_rwlock_rdunlock ( &_lock ) ;
   }

   bool try_get_shared ()
   {
      return ( oss_rwlock_rdtrylock ( &_lock ) ) ;
   }
} ;
#endif
           

(1)這裡的互斥鎖和共享鎖分别是對作業系統中的互斥鎖和讀寫鎖的簡單封裝

(2)對系統調用用宏定義取别名,展現了oss層對平台相關系統調用的封裝的思想

(3)我們的資料庫是用線程池的架構,本身要求有線程切換,是以不必用自旋鎖來提高效率

三、隊列的概述

#ifndef OSSQUEUE_HPP__
#define OSSQUEUE_HPP__

#include <queue>
#include <boost/thread.hpp>
#include <boost/thread/thread_time.hpp>

#include "core.hpp"

template<typename Data>
class ossQueue
{
private :
   std::queue<Data> _queue ;//隊列
   boost::mutex _mutex ;//互斥鎖
   boost::condition_variable _cond ;//條件變量
public :
   unsigned int size ()//隊列大小
   {
      boost::mutex::scoped_lock lock ( _mutex ) ;//加鎖
      return (unsigned int)_queue.size () ;
   }

   void push ( Data const &data )//壓入靜态資料
   {
      boost::mutex::scoped_lock lock ( _mutex ) ;
      _queue.push ( data ) ;
      lock.unlock () ;//解鎖
      _cond.notify_one () ;//喚醒一個等待條件變量的線程
   }

   bool empty () const
   {
      boost::mutex::scoped_lock lock ( _mutex ) ;
      return _queue.empty () ;
   }

   bool try_pop ( Data &value )//嘗試彈出
   {
      boost::mutex::scoped_lock lock ( _mutex ) ;
      if ( _queue.empty () )
         return false ;
      value = _queue.front () ;
      _queue.pop () ;
      return true ;
   }

   void wait_and_pop ( Data &value )//等待并且彈出
   {
      boost::mutex::scoped_lock lock ( _mutex ) ;
      while ( _queue.empty () )
      {
         _cond.wait ( lock ) ;//等待的時候會釋放鎖,條件發生後就會得帶鎖
      }
      value = _queue.front () ;
      _queue.pop () ;
   }

   bool timed_wait_and_pop ( Data &value, long long millsec )
   {
      boost::system_time const timeout = boost::get_system_time () +
            boost::posix_time::milliseconds(millsec) ;
      boost::mutex::scoped_lock lock ( _mutex ) ;
      // if timed_wait return false, that means we failed by timeout
      while ( _queue.empty () )
      {
         if ( !_cond.timed_wait ( lock, timeout ) )//帶有逾時時間的去等待條件
         {
            return false ;
         }
      }
      value = _queue.front () ;
      _queue.pop () ;
      return true ;
   }
} ;
#endif
           

(1)多線程中的消息隊列是共享資源,是以在對隊列進行操作時必須加鎖

(2)線程間的同步主要用條件變量來實作,值得注意的是條件變量的使用一定伴随着一個互斥鎖

(3)這裡用到了boost中的互斥鎖和條件變量,但實際上使用博文《實作一個線程池》中的互斥鎖和條件變量包裝類也可以。