@synchronized深入理解
@synchronized是线程同步锁,易用、可读性高。
@synchronized(self) {
临界区
}
利用如下命令将其重写
clang -rewrite-objc file
得到C++实现
{
id _sync_obj = (id)self;
objc_sync_enter(_sync_obj);
struct _SYNC_EXIT {
_SYNC_EXIT(id arg) : sync_exit(arg) {}
~_SYNC_EXIT() {
objc_sync_exit(sync_exit);
}
id sync_exit;
} _sync_exit(_sync_obj);
}
深究objc_sync_enter和objc_sync_exit的源码
int objc_sync_enter(id obj)
{
if (obj) {
SyncData* data = id2data(obj, ACQUIRE);
recursive_mutex_lock(&data->mutex); // 获取递归锁
} else {
// @synchronized(nil) does nothing
}
}
int objc_sync_exit(id obj)
{
if (obj) {
SyncData* data = id2data(obj, RELEASE);
recursive_mutex_unlock(&data->mutex); // 释放递归锁
} else {
// @synchronized(nil) does nothing
}
}
可以看到
1、@synchronized底层用的是递归锁,即同个线程可重入,而不会导致死锁。
2、@synchronized(nil)是不会上锁的。
接着,显然SyncList是单链表,SyncData是其中的节点,而整体的存储则是一个“拉链哈希表”。
typedef struct SyncData {
struct SyncData* nextData; // 指向下一个SyncData节点
DisguisedPtr<objc_object> object; // @synchronized的参数,即上面的self
recursive_mutex_t mutex; // 递归锁
} SyncData;
struct SyncList {
SyncData *data; // 单链表的头指针
spinlock_t lock; // 自旋锁,性能好,但不绝对安全
SyncList() : data(nil) { }
};
#define LOCK_FOR_OBJ(obj) sDataLists[obj].lock // 根据参数获取单链表的锁
#define LIST_FOR_OBJ(obj) sDataLists[obj].data // 根据参数获取单链表
static StripedMap<SyncList> sDataLists; // 哈希表
// 根据参数获取对应的SyncData节点,其实就是哈希表查找
static SyncData* id2data(id object, enum usage why)
{
spinlock_t *lockp = &LOCK_FOR_OBJ(object);
SyncData **listp = &LIST_FOR_OBJ(object); // 参数对应的单链表
SyncData* result = NULL; lockp->lock();
{
SyncData* p;
// 遍历单链表
for (p = *listp; p != NULL; p = p->nextData) {
if ( p->object == object ) {
// 找到参数对应的SyncData节点
result = p;
goto done;
}
}
}
// 单链表中还没有参数对应的SyncData节点
result = (SyncData*)calloc(sizeof(SyncData), 1);
result->object = (objc_object *)object; // 填充数据
new (&result->mutex) recursive_mutex_t();
// 新建的SyncData节点往链表头部加
result->nextData = *listp;
*listp = result;
done:
lockp->unlock();
return result;
}
template<typename T>
class StripedMap {
static unsigned int indexForPointer(const void *p) {
// 取参数地址的哈希值作为数组的index
uintptr_t addr = reinterpret_cast<uintptr_t>(p);
return ((addr >> 4) ^ (addr >> 9)) % StripeCount;
}
public:
T& operator[] (const void *p) {
return array[indexForPointer(p)].value;
}
};

可以看出,参数和递归锁是一一对应的。因此,一定要保证参数不变,这里的不变,指的是完全不变,包括地址。
源码:
https://opensource.apple.com/source/objc4/objc4-680/runtime/objc-sync.mm
@synchronized深入理解的更多相关文章
- 对于synchronized的理解
一.synchronized 同步关键字,分为同步代码块和同步函数 二.对synchronized的理解(未加static关键字)(以下所说:对同步方法和同步代码块均适用) 对象的创建是以类为模板的 ...
- Java中synchronized关键字理解
好记性不如烂笔头~~ 并发编程中synchronized关键字的地位很重要,很多人都称它为重量级锁.利用synchronized实现同步的基础:Java中每一个对象都可以作为锁.具体表现为以下三种形式 ...
- synchronized的理解
用法解释 synchronized是Java中的关键字,是一种同步锁.它修饰的对象有以下几种: 1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调 ...
- Java线程同步synchronized的理解
JVM中(留神:马上讲到的这两个存储区只在JVM内部与物理存储区无关)存在一个主内存(Main Memory),Java中所有的变量存储在主内存中,所有实例和实例的字段都在此区域,对于所有的线程是共享 ...
- synchronized(this) 与 synchronized(class) 理解
1.概念 synchronized 是 Java 中的关键字,是利用锁的机制来实现同步的. 锁机制有如下两种特性: 互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机 ...
- java并发编程--Synchronized的理解
synchronized实现锁的基础:Java中每一个对象都可以作为锁,具体表现为3种形式. (1)普通同步方法,锁是当前实例对象 (2)静态同步方法,锁是当前类的Class对象 (3)同步方法块,锁 ...
- 【多线程与高并发原理篇:4_深入理解synchronized】
1. 前言 越是简单的东西,在深入了解后发现越复杂.想起了曾在初中阶段,语文老师给我们解说<论语>的道理,顺便给我们提了一句,说老子的无为思想比较消极,学生时代不要太关注.现在有了一定的生 ...
- volatile synchronized AtomicInteger的区别
在网络上看了很多关于他们两个的区别与联系,今天用自己的话表述一下: synchronized 容易理解,给一个方法或者代码的一个区块加锁,那么需要注意的是,加锁的标志位默认是this对象,当然聪明的你 ...
- Synchronized用法原理和锁优化升级过程(面试)
简介 多线程一直是面试中的重点和难点,无论你现在处于啥级别段位,对synchronized关键字的学习避免不了,这是我的心得体会.下面咱们以面试的思维来对synchronized做一个系统的描述,如果 ...
随机推荐
- Python全栈学习_day001知识点
今日大纲: . 变量. ***** . 常量.** . 注释.*** . 基础数据类型初识(int,str,bool). ***** . 用户输入 input ***** . 流程控制语句if. ** ...
- js+springMVC 提交数组数据到后台
1.ajax 代码 var ids =new Array(); $.ajax({ type: "POST", url: "/user/downReport", ...
- java获取文件路径
情况:工程项目没有放到tomcat下,在eclipse运行 1.获取项目根目录,根据在哪里运行 2. 3.从最终生成的.class文件为着手点 4.在controller下
- python自动化开发-6
python的常用模块(续) shutil模块:主要是做文件复制的.文件,文件夹,压缩包等的处理模块. 常用的方法: shutil.copyfileobj:将文件的内容拷贝到另一个文件中. 例子: # ...
- Appium学习——Appium工作原理
appium的工具原理 Appium-client>>>>Appium-server>>>>移动设备 ========================= ...
- [20170914]tnsnames.ora的管理.txt
[20170914]tnsnames.ora的管理.txt --//昨天朋友讲tnsnams.ora的内容太长了,而且许多不需要的.管理不方便.我记得以前写[20150409]tnsnames.ora ...
- 洗礼灵魂,修炼python(16)--列表进阶话题—>上节作业讲解+copy模块,浅拷贝,深拷贝
上节课后作业: 1.使用列表解析输出结果:[(0,0),(0,2),(2,0),(2,2)] 方法1: 方法2: 方法3: 2.使用列表生成器打印斐波那契数列 3.使用列表解析生成列表[1x2,3x4 ...
- Gogs基本使用介绍
Gogs简介 Gogs 是一款类似GitHub的开源文件/代码管理系统(基于Git),Gogs 的目标是打造一个最简单.最快速和最轻松的方式搭建自助 Git 服务.使用 Go 语言开发使得 Gogs ...
- ccf--20151203--画图
本题思路如下: 题目和代码如下: 问题描述 试题编号: 201512-3 试题名称: 画图 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 用 ASCII 字符来画图是一件有趣 ...
- C++基础算法学习——汉洛塔问题
汉诺塔问题古代有一个梵塔,塔内有三个座A.B.C,A座上有64个盘子,盘子大小不等,大的在下,小的在上(如图).有一个和尚想把这64个盘子从A座移到C座,但每次只能允许移动一个盘子,并且在移动过程中, ...