返回
iOS多线程(三):探秘@synchronized源码与单向链表的巧妙应用
IOS
2023-10-18 03:58:28
引言
探究源码不仅可以揭开事物的运作机制,还能让我们领略大师的匠心设计。本文将带你深入剖析@synchronized
的源码,领略苹果工程师对单向链表的巧妙运用。本文基于objc4-818.2源码展开。
揭开@synchronized源码的神秘面纱
@synchronized
是Objective-C中用于多线程同步的关键手段,其源码精妙绝伦。下面逐一解析:
id objc_sync_enter(id obj) {
if (!obj) {
return 0;
}
os_unfair_lock_lock(&_objc_runtime->sync_lock);
id *tail = &_objc_runtime->sync_tail;
while (*tail != NULL) {
if (*tail == obj) {
// 相同锁,尝试解锁,若失败说明已被其他线程抢占
if (os_unfair_lock_trylock(&_objc_runtime->sync_lock)) {
os_unfair_lock_unlock(&_objc_runtime->sync_lock);
return tail;
}
}
tail = &(*tail)->next;
}
// 不同锁,创建一个新的Node
struct objc_sync_node *node = (struct objc_sync_node *)malloc(sizeof(struct objc_sync_node));
node->obj = obj;
node->next = NULL;
*tail = node;
os_unfair_lock_unlock(&_objc_runtime->sync_lock);
return node;
}
- 检查参数有效性: 首先判断目标对象是否为空,如果是则直接返回0。
- 进入临界区: 使用
os_unfair_lock_lock()
进入临界区,保护后续操作的安全性。 - 遍历单向链表: 通过
_objc_runtime->sync_tail
指向的单向链表,遍历所有已存在的锁对象。 - 检查目标对象是否存在: 如果当前遍历的锁对象与目标对象相等,则说明目标对象已被锁定。
- 尝试解锁: 使用
os_unfair_lock_trylock()
尝试解锁该锁对象。如果成功,说明该锁对象未被其他线程持有;否则,说明该锁对象已被其他线程抢占,需要继续遍历。 - 创建新节点: 如果遍历完整个链表都没有找到目标对象,则创建一个新的单向链表节点
node
,将其obj
指向目标对象,next
指向NULL,并将node
追加到链表尾部。 - 退出临界区: 最后,使用
os_unfair_lock_unlock()
退出临界区,完成@synchronized
的进入操作。
单向链表的巧妙应用
@synchronized
源码中巧妙地使用了单向链表来管理锁对象。这带来以下好处:
- 高效遍历: 单向链表的遍历仅需沿着链表指向的方向进行,无需反向遍历,提高了效率。
- 快速查找: 通过将新创建的节点追加到链表尾部,可以快速找到目标对象,降低查找时间复杂度。
- 可扩展性: 单向链表的结构简单,易于扩展,可以根据需要动态添加和删除节点。
结语
通过分析@synchronized
的源码,我们领略到了苹果工程师对单向链表的巧妙应用。这种设计不仅保证了多线程同步的安全性,还提供了高效、可扩展的锁对象管理机制。深入源码的探究不仅开拓了我们的视野,也激发了我们对底层原理的思考。