一、锁的概述
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中的互斥锁和条件变量,但实际上使用博文《实现一个线程池》中的互斥锁和条件变量包装类也可以。