SQLite3源码学习(18) 互斥锁
互斥锁是为了保证在多线程时一些不可重入函数执行的串行化,有些函数如malloc等会操作一些共享数据,如果被重入了就会导致共享资源被破坏,从而出现逻辑错误,所以如果有多个线程对共享资源的访问就要加互斥锁。
互斥锁部分的代码还是比较简单的,代码实现在mutex.c、mutex_w32.c、mutex_unix.c和mutex_noop.c这几个文件里,另外还有一个test_mutex.c文件做mutex的相关测试。
1.使用
这里以malloc.c里对互斥锁的使用先举个例子
sqlite3MutexInit();//在程序启动时要先初始化互斥锁接口
……
mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);//新建互斥锁,并分配空间,参数是锁的类型
……
sqlite3_mutex_enter(mem0.mutex);//进入临界区先加锁,如果已经有其他线程在使用该锁,那么线程会挂起,等待锁释放。
……//临界区
sqlite3_mutex_leave(mem0.mutex); //离开临界区时释放锁
2.初始化
将真实的mutex接口保存在sqlite3GlobalConfig.mutex,实际使用时只要调用保存接口的函数指针就可以了。
如果用户确定不使用多线程,还可以把锁接口配置成NoopMutex,该接口不存在互斥锁,使用于单线程的程序,速度会更快。
int sqlite3MutexInit(void){ int rc = SQLITE_OK;if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){/* If the xMutexAlloc method has not been set, then the user did not** install a mutex implementation via sqlite3_config() prior to ** sqlite3_initialize() being called. This block copies pointers to** the default implementation into the sqlite3GlobalConfig structure.*/sqlite3_mutex_methods const *pFrom;sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;//保存互斥锁的使用接口if( sqlite3GlobalConfig.bCoreMutex ){pFrom = sqlite3DefaultMutex();//默认接口}else{pFrom = sqlite3NoopMutex();//不使用互斥锁,适用于单线程}pTo->xMutexInit = pFrom->xMutexInit;pTo->xMutexEnd = pFrom->xMutexEnd;pTo->xMutexFree = pFrom->xMutexFree;pTo->xMutexEnter = pFrom->xMutexEnter;pTo->xMutexTry = pFrom->xMutexTry;pTo->xMutexLeave = pFrom->xMutexLeave;pTo->xMutexHeld = pFrom->xMutexHeld;pTo->xMutexNotheld = pFrom->xMutexNotheld;sqlite3MemoryBarrier();//这是一个内存屏障,为了防止某些cpu指令的乱序执行pTo->xMutexAlloc = pFrom->xMutexAlloc;}assert( sqlite3GlobalConfig.mutex.xMutexInit );rc = sqlite3GlobalConfig.mutex.xMutexInit();#ifdef SQLITE_DEBUGGLOBAL(int, mutexIsInit) = 1;
#endifreturn rc;
}
用户可以使用以下2个函数来获取mutex接口和更新接口,一般测试时会获取原来的接口,把原来的接口插入到自定的接口里做错误模拟,如
sqlite3_config(SQLITE_CONFIG_GETMUTEX, &wrapped.mutex);
sqlite3_config(SQLITE_CONFIG_MUTEX, &mutexmethods);
3.具体接口
win32下使用api接口有:
InitializeCriticalSection(&p->mutex);//初始化临界区
EnterCriticalSection(&p->mutex);//访问临界区,没有锁资源则挂起线程
LeaveCriticalSection(&p->mutex);//离开临界区
TryEnterCriticalSection(&p->mutex)//尝试访问临界区,没有锁资源则返回
DeleteCriticalSection(&p->mutex);//删除锁,释放p->mutex的空间
在linux下有类似的api接口pthread_mutex,这里就不一一介绍了。
锁类型为SQLITE_MUTEX_FAST和SQLITE_MUTEX_RECURSIVE的锁需要动态申请空间,其他类型的锁为静态分配的空间。
static sqlite3_mutex *winMutexAlloc(int iType){sqlite3_mutex *p;switch( iType ){case SQLITE_MUTEX_FAST:case SQLITE_MUTEX_RECURSIVE: {p = sqlite3MallocZero( sizeof(*p) );if( p ){p->id = iType;InitializeCriticalSection(&p->mutex);}break;}default: {p = &winMutex_staticMutexes[iType-2];p->id = iType;break;}}return p;
}
静态锁初始化时要调用winMutexInit()函数
static int winMutexInit(void){/* The first to increment to 1 does actual initialization */if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){int i;for(i=0; i<ArraySize(winMutex_staticMutexes); i++){InitializeCriticalSection(&winMutex_staticMutexes[i].mutex);// 初始化静态锁}winMutex_isInit = 1;}else{/* Another thread is (in the process of) initializing the static** mutexes */while( !winMutex_isInit ){sqlite3_win32_sleep(1);}}return SQLITE_OK;
}
在访问临界区时会获取线程id并且增加引用计数,所以一般在前期测试时,在有些必须要加锁的地方可以对winMutexHeld()函数的返回值做断言,防止在访问临界区时忘加锁了。
static void winMutexEnter(sqlite3_mutex *p){
DWORD tid = GetCurrentThreadId();
……EnterCriticalSection(&p->mutex);assert( p->nRef>0 || p->owner==0 );p->owner = tid;p->nRef++;
……
}
static int winMutexHeld(sqlite3_mutex *p){return p->nRef!=0 && p->owner==GetCurrentThreadId();
}
SQLite3源码学习(18) 互斥锁相关推荐
- SQLite3源码学习(32) WAL日志详细分析
在前面2篇文章讲了有关WAL日志相关的一些基础知识: SQLite3源码学习(31) WAL日志的锁机制 SQLite3源码学习(30)WAL-Index文件中的hash表 接下来分析一下在WAL日志 ...
- MySQL mdl导入_MySQL源码学习——MDL字典锁
什么是MDL MDL,Meta Data lock,元数据锁,一般称为字典锁.字典锁与数据锁相对应.字典锁是为了保护数据对象被改变,一般是一些DDL会对字典对象改变,如两个TX,TX1先查询表,然后T ...
- Swoole源码学习记录(五)——锁和信号(二)
Swoole版本:1.7.4-stable Github地址: https://github.com/LinkedDestiny/swoole-src-analysis 二.Mutex互斥锁 接下来是 ...
- PHP 源码学习之线程安全
PHP 源码学习之线程安全 了解线程安全之前,我们先回顾几点基础知识点,是我们后面分析学习的基础. 变量的作用域 从作用域上来说,C语言可以定义4种不同的变量:全局变量,静态全局变量,局部变量,静态局 ...
- Shiro源码学习之二
接上一篇 Shiro源码学习之一 3.subject.login 进入login public void login(AuthenticationToken token) throws Authent ...
- (0045) iOS 开发之MBProgressHUD 源码学习
(0045) iOS 开发之MBProgressHUD 源码学习 第一部分:学习所得和分析线程 1. 学习到了kvo 的使用 和屏幕方向的旋转判断. 2. 如果调起这个 HUD 的方法不是在主线程调 ...
- Java 源码学习系列(三)——Integer
Integer 类在对象中包装了一个基本类型 int 的值.Integer 类型的对象包含一个 int 类型的字段. 此外,该类提供了多个方法,能在 int 类型和 String 类型之间互相转换,还 ...
- 以太坊源码学习 -- EVM
以太坊源码学习 – EVM 学习文档链接:here 一.虚拟机外 主要功能: 执行前将Transaction类型转化成Message,创建虚拟机(EVM)对象,计算一些Gas消耗,以及执行交易完毕后创 ...
- ConcurrentHashMap源码学习
ConcurrentHashMap源码学习 自从学习了AQS之后,想着重新读一下ConcurrentHashMap的源码来加深下理解,所以有了这篇文章,针对ConcurrentHashMap常用的方法 ...
最新文章
- csharp通过dll调用opencv函数,图片作为参数
- 数据结构与算法 | 用栈实现队列
- centos7根据端口查进程_记录一次CentOs7下Nginx+WSGI部署Django项目(超详细)
- mac eclipse tomcat mysql_mac下使用eclipse+tomcat+mysql开发 j2ee(一)
- linux fcntl
- Hostiko v54.0 – WordPress WHMCS-云服务器VPS主机销售模板源码
- 华为已经升级鸿蒙系统的机型,鸿蒙系统名单已确认!覆盖55款机型,这些手机将被淘汰!...
- 转录组分析_转录组分析 | 使用Stringtie对数据进行下游处理
- 如何把手机变成你的救生设备
- php ddos 防御,PHP DDos的几个防御方法
- 一张图慢慢转换成下一张图_如何把一张照片变成炫酷的动图?
- 【lssvm分类】基于粒子群算法优化最小二乘支持向量机lssvm实现数据分类matlab代码
- Windows XP SP3需要安装KB888111补丁解决方法
- c语言 r语言 java,R语言rJava包安装载入及JAVA环境配置
- 类似PS的蒙版?可以实现,LVGL『Object mask对象蒙版控件』介绍
- 开发板搭建简单的Web服务器
- 三角形中的正方形,三个问题
- C语言中的switch语句基本用法
- 图像处理方面的sci期刊_图像处理领域的SCI期刊.doc
- 你了解DSP芯片的发展吗?DSP芯片有哪些应用?