@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深入理解的更多相关文章

  1. 对于synchronized的理解

    一.synchronized 同步关键字,分为同步代码块和同步函数 二.对synchronized的理解(未加static关键字)(以下所说:对同步方法和同步代码块均适用) 对象的创建是以类为模板的 ...

  2. Java中synchronized关键字理解

    好记性不如烂笔头~~ 并发编程中synchronized关键字的地位很重要,很多人都称它为重量级锁.利用synchronized实现同步的基础:Java中每一个对象都可以作为锁.具体表现为以下三种形式 ...

  3. synchronized的理解

    用法解释 synchronized是Java中的关键字,是一种同步锁.它修饰的对象有以下几种: 1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调 ...

  4. Java线程同步synchronized的理解

    JVM中(留神:马上讲到的这两个存储区只在JVM内部与物理存储区无关)存在一个主内存(Main Memory),Java中所有的变量存储在主内存中,所有实例和实例的字段都在此区域,对于所有的线程是共享 ...

  5. synchronized(this) 与 synchronized(class) 理解

    1.概念 synchronized 是 Java 中的关键字,是利用锁的机制来实现同步的. 锁机制有如下两种特性: 互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机 ...

  6. java并发编程--Synchronized的理解

    synchronized实现锁的基础:Java中每一个对象都可以作为锁,具体表现为3种形式. (1)普通同步方法,锁是当前实例对象 (2)静态同步方法,锁是当前类的Class对象 (3)同步方法块,锁 ...

  7. 【多线程与高并发原理篇:4_深入理解synchronized】

    1. 前言 越是简单的东西,在深入了解后发现越复杂.想起了曾在初中阶段,语文老师给我们解说<论语>的道理,顺便给我们提了一句,说老子的无为思想比较消极,学生时代不要太关注.现在有了一定的生 ...

  8. volatile synchronized AtomicInteger的区别

    在网络上看了很多关于他们两个的区别与联系,今天用自己的话表述一下: synchronized 容易理解,给一个方法或者代码的一个区块加锁,那么需要注意的是,加锁的标志位默认是this对象,当然聪明的你 ...

  9. Synchronized用法原理和锁优化升级过程(面试)

    简介 多线程一直是面试中的重点和难点,无论你现在处于啥级别段位,对synchronized关键字的学习避免不了,这是我的心得体会.下面咱们以面试的思维来对synchronized做一个系统的描述,如果 ...

随机推荐

  1. API接口规范V1.0——制定好规范,才好合作开发

    返回码规范: 统一六位 000000 表示成功! 参数相关返回码预留100000-199999:系统相关返回码预留200000-299999:数据中心310000-319999后续项目以此类推,后续根 ...

  2. linux中cut、printf、awk、sed命令

    cut.printf.awk.sed在linux中都是用来处理文本的命令,接下来一个一个看. 一.cut命令 cut [选项] 文件名 选项: 主要使用一下两个参数,若是只使用 -f 则默认的分割符为 ...

  3. js-MediumGrade-base.js

    // 1.JavaScript 中的类型包括 Number(数字) String(字符串) Boolean(布尔) Symbol(符号)(第六版新增) Object(对象) Function(函数) ...

  4. 【工具相关】web-HTML/CSS/JS Prettify的使用

    一,打开Sublime Text,代码如下面所示. 二,鼠标右键--->HTML/CSS/JS Prettify--->Prettify Code.代码如图所示,明显的代码变得整齐了.

  5. 【读书笔记】iOS-软件测试与iOS测试

    一,软件测试的类型. 1.软件测试按照测试类型,可以划分为:单元测试,集成测试和系统测试. 2.单元测试是指对软件系统中最小可测试单元进行的检查和验证. 3.集成测试,在iOS软件开发中,集成测试主要 ...

  6. SAP MM PIR里的Lower Limit & Upper Limit

    SAP MM PIR里的Lower Limit & Upper Limit 在PIR的价格的detail数据里,有2个字段:Lower Limit和Upper Limit.在今天之前,笔者从未 ...

  7. 将你的 Virtual dom 渲染成 Canvas

    项目概述 一个基于Vue的virtual dom插件库,按照Vue render 函数的写法,直接将Vue生成的Vnode渲染到canvas中.支持常规的滚动操作和一些基础的元素事件绑定. githu ...

  8. C#微信公众号开发——获取access_token

    access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token.正常情况下access_token有效期为7200秒(两个小时),微信获取access_token接 ...

  9. [转]js版的md5()

    转自:http://blog.163.com/a_hc/blog/static/1623434200831832441896/ <script language=javascript>/* ...

  10. alsa声卡分析alsa-utils调用过程(二)-tinymixer

    继上一篇文章:http://www.cnblogs.com/linhaostudy/p/8515277.html 三.tinymixer调用分析:(tinymixer.log搜索节点:/dev/snd ...