互斥锁是为了保证在多线程时一些不可重入函数执行的串行化,有些函数如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) 互斥锁相关推荐

  1. SQLite3源码学习(32) WAL日志详细分析

    在前面2篇文章讲了有关WAL日志相关的一些基础知识: SQLite3源码学习(31) WAL日志的锁机制 SQLite3源码学习(30)WAL-Index文件中的hash表 接下来分析一下在WAL日志 ...

  2. MySQL mdl导入_MySQL源码学习——MDL字典锁

    什么是MDL MDL,Meta Data lock,元数据锁,一般称为字典锁.字典锁与数据锁相对应.字典锁是为了保护数据对象被改变,一般是一些DDL会对字典对象改变,如两个TX,TX1先查询表,然后T ...

  3. Swoole源码学习记录(五)——锁和信号(二)

    Swoole版本:1.7.4-stable Github地址: https://github.com/LinkedDestiny/swoole-src-analysis 二.Mutex互斥锁 接下来是 ...

  4. PHP 源码学习之线程安全

    PHP 源码学习之线程安全 了解线程安全之前,我们先回顾几点基础知识点,是我们后面分析学习的基础. 变量的作用域 从作用域上来说,C语言可以定义4种不同的变量:全局变量,静态全局变量,局部变量,静态局 ...

  5. Shiro源码学习之二

    接上一篇 Shiro源码学习之一 3.subject.login 进入login public void login(AuthenticationToken token) throws Authent ...

  6. (0045) iOS 开发之MBProgressHUD 源码学习

    (0045) iOS 开发之MBProgressHUD 源码学习 第一部分:学习所得和分析线程 1.  学习到了kvo 的使用 和屏幕方向的旋转判断. 2. 如果调起这个 HUD 的方法不是在主线程调 ...

  7. Java 源码学习系列(三)——Integer

    Integer 类在对象中包装了一个基本类型 int 的值.Integer 类型的对象包含一个 int 类型的字段. 此外,该类提供了多个方法,能在 int 类型和 String 类型之间互相转换,还 ...

  8. 以太坊源码学习 -- EVM

    以太坊源码学习 – EVM 学习文档链接:here 一.虚拟机外 主要功能: 执行前将Transaction类型转化成Message,创建虚拟机(EVM)对象,计算一些Gas消耗,以及执行交易完毕后创 ...

  9. ConcurrentHashMap源码学习

    ConcurrentHashMap源码学习 自从学习了AQS之后,想着重新读一下ConcurrentHashMap的源码来加深下理解,所以有了这篇文章,针对ConcurrentHashMap常用的方法 ...

最新文章

  1. csharp通过dll调用opencv函数,图片作为参数
  2. 数据结构与算法 | 用栈实现队列
  3. centos7根据端口查进程_记录一次CentOs7下Nginx+WSGI部署Django项目(超详细)
  4. mac eclipse tomcat mysql_mac下使用eclipse+tomcat+mysql开发 j2ee(一)
  5. linux fcntl
  6. Hostiko v54.0 – WordPress WHMCS-云服务器VPS主机销售模板源码
  7. 华为已经升级鸿蒙系统的机型,鸿蒙系统名单已确认!覆盖55款机型,这些手机将被淘汰!...
  8. 转录组分析_转录组分析 | 使用Stringtie对数据进行下游处理
  9. 如何把手机变成你的救生设备
  10. php ddos 防御,PHP DDos的几个防御方法
  11. 一张图慢慢转换成下一张图_如何把一张照片变成炫酷的动图?
  12. 【lssvm分类】基于粒子群算法优化最小二乘支持向量机lssvm实现数据分类matlab代码
  13. Windows XP SP3需要安装KB888111补丁解决方法
  14. c语言 r语言 java,R语言rJava包安装载入及JAVA环境配置
  15. 类似PS的蒙版?可以实现,LVGL『Object mask对象蒙版控件』介绍
  16. 开发板搭建简单的Web服务器
  17. 三角形中的正方形,三个问题
  18. C语言中的switch语句基本用法
  19. 图像处理方面的sci期刊_图像处理领域的SCI期刊.doc
  20. 你了解DSP芯片的发展吗?DSP芯片有哪些应用?

热门文章

  1. JS实现植物大战僵尸小游戏,代码记录及效果展示
  2. HDFS启动的时候出现JAVA_HOME is not set and could not be found.
  3. java人职业规划(摘要)
  4. 简单介绍一下CAD做三维图的REVOLVE指令
  5. 【安全资讯】梅开二度,Chrome再次被曝0day漏洞
  6. 2015百度沸点榜单
  7. 电力系统中的定值区是什么意思
  8. 身份证验证接口API(仅需一行代码,公安部实时接口)
  9. 深度学习之图像分类(十四)--ShuffleNetV2 网络结构
  10. win7安装office2007失败