关于@synchronized

一、结论

  1)@synchronized内部使用的是recursive_mutex_lock,也就是递归锁,对于统一线程来说,@synchronized加锁的方法可以重复加锁。

  比如代码:

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self testA];
}
 
- (void)testA
{
    @synchronized(self)
    {
        NSLog(@"AAAAAA");
        [self testB];
    }
}
 
- (void)testB
{
    @synchronized(self)
    {
        NSLog(@"BBBBBB");
    }
}

   输出结果为:

  

1
2
2018-08-21 15:25:51.058333+0800 TestSynchronized2[17367:7864821] AAAAAA
2018-08-21 15:25:51.058372+0800 TestSynchronized2[17367:7864821] BBBBBB

  

  2)@synchronized 可以看成一个函数,加锁的对象是后面传入对象的地址,所以如果加锁对象重新赋值,那么地址会重新该表导致加锁失效。

     如果这个对象为nil,那么等于没有加锁。

    内部实现源代码如下:

    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
static void _I_Demo_synchronizedTest(Demo * self, SEL _cmd) {
    NSMutableArray *arr;
    {
      id _sync_obj = (id)arr;
      objc_sync_enter(_sync_obj); // 同步锁进入,参数是arr
        try {
            struct _SYNC_EXIT {
                _SYNC_EXIT(id arg) : sync_exit(arg) {} 
                ~_SYNC_EXIT() {objc_sync_exit(sync_exit); // 同步锁退出,参数是arr
  }
            id sync_exit;
        }   _sync_exit(_sync_obj);// 调用结构体的构造函数,参数是arr
          } catch (id e) {
      }
   }
}
 
int objc_sync_enter(id obj)
    {
              int result = OBJC_SYNC_SUCCESS;
              if (obj) {
            // 根据obj获取对应的SyncData节点,id2data函数在下面有解析
            SyncData* data = id2data(obj, ACQUIRE);// 上锁
            result = recursive_mutex_lock(&data->mutex); }
        else
          { // @synchronized(nil) does nothing
    }
       return result;
    }
 
typedef struct SyncData {
             struct SyncData* nextData; // 指向下一个SyncData节点的指针
             DisguisedPtr<objc_object> object; // @synchronized的参数obj
             int32_t threadCount; // number of THREADS using this block  
             recursive_mutex_t mutex; // 递归锁
          } SyncData;
 
        struct SyncList {
               SyncData *data; // 单链表头指针
               spinlock_t lock; // 保证多线程安全访问该链表
               SyncList() : data(nil) { }
        };
 
static StripedMap<SyncList> sDataLists; // 哈希表,key:obj,value:单链表
 
      // 根据obj获取对应的SyncData节点static SyncData* id2data(id object, enum usage why)
      {
          spinlock_t *lockp = &LOCK_FOR_OBJ(object); // SyncList锁
         SyncData **listp = &LIST_FOR_OBJ(object); // obj对应的SyncData节点所在的
        SyncList SyncData* result = NULL;// 这里省略一大坨cache代码
 
        lockp->lock();
        {
            SyncData* p;
            SyncData* firstUnused = NULL;
       // 遍历单链表
            for (p = *listp; p != NULL; p = p->nextData) {
                  if ( p->object == object ) {
              // 找到obj对应的SyncData节点
                  result = p;
                // SyncData节点对应的线程数加1 
                 OSAtomicIncrement32Barrier(&result->threadCount);
                  goto done;
        }
    // SyncData节点对应的递归锁没有线程在用了,回收重用,可以节省节点创建的时间和空间
      if ( (firstUnused == NULL) && (p->threadCount == 0) )
                    firstUnused = p;
            }
     // 链表中还没有obj对应的SyncData节点,但是有可重用的SyncData节点
    // an unused one was found, use it
             if ( firstUnused != NULL ) {
                  result = firstUnused;
                  result->object = (objc_object *)object;
                  result->threadCount = 1;
                  goto done;
            }
        }
// 链表中还没有obj对应的SyncData节点,而且没有可重用的SyncData节点
       result = (SyncData*)calloc(sizeof(SyncData), 1);
       result->object = (objc_object *)object;
       result->threadCount = 1;
       new (&result->mutex) recursive_mutex_t();
// 新建的SyncData节点往链表头部加
       result->nextData = *listp;
       *listp = result;
 done:
       lockp->unlock();
       return result;}

  

  3)swift中没有对应的方法,但是依然可以使用OC中调用加锁的函数,实现如下

  

1
2
3
4
5
func synchronized<T>(_ lock: AnyObject, _ body: () throws -> T) rethrows -> T {
        objc_sync_enter(lock)
        defer { objc_sync_exit(lock) }
        return try body()
    }

  

 

参考资料:

  作者:悲观患者
  链接:https://www.jianshu.com/p/d83b3b7d5a5a

    

posted @   兜兜有糖的博客  阅读(1048)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示