返回

iOS多线程(三):探秘@synchronized源码与单向链表的巧妙应用

IOS

引言

探究源码不仅可以揭开事物的运作机制,还能让我们领略大师的匠心设计。本文将带你深入剖析@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;
}
  1. 检查参数有效性: 首先判断目标对象是否为空,如果是则直接返回0。
  2. 进入临界区: 使用os_unfair_lock_lock()进入临界区,保护后续操作的安全性。
  3. 遍历单向链表: 通过_objc_runtime->sync_tail指向的单向链表,遍历所有已存在的锁对象。
  4. 检查目标对象是否存在: 如果当前遍历的锁对象与目标对象相等,则说明目标对象已被锁定。
  5. 尝试解锁: 使用os_unfair_lock_trylock()尝试解锁该锁对象。如果成功,说明该锁对象未被其他线程持有;否则,说明该锁对象已被其他线程抢占,需要继续遍历。
  6. 创建新节点: 如果遍历完整个链表都没有找到目标对象,则创建一个新的单向链表节点node,将其obj指向目标对象,next指向NULL,并将node追加到链表尾部。
  7. 退出临界区: 最后,使用os_unfair_lock_unlock()退出临界区,完成@synchronized的进入操作。

单向链表的巧妙应用

@synchronized源码中巧妙地使用了单向链表来管理锁对象。这带来以下好处:

  1. 高效遍历: 单向链表的遍历仅需沿着链表指向的方向进行,无需反向遍历,提高了效率。
  2. 快速查找: 通过将新创建的节点追加到链表尾部,可以快速找到目标对象,降低查找时间复杂度。
  3. 可扩展性: 单向链表的结构简单,易于扩展,可以根据需要动态添加和删除节点。

结语

通过分析@synchronized的源码,我们领略到了苹果工程师对单向链表的巧妙应用。这种设计不仅保证了多线程同步的安全性,还提供了高效、可扩展的锁对象管理机制。深入源码的探究不仅开拓了我们的视野,也激发了我们对底层原理的思考。