<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          iOS @synchronized() 底層原理探索

          共 10285字,需瀏覽 21分鐘

           ·

          2021-10-24 08:45

          ????關(guān)注后回復(fù) “進(jìn)群” ,拉你進(jìn)程序員交流群????

          作者:自如大前端研發(fā)中心-李長(zhǎng)鴻

          https://juejin.cn/post/7017703842594684935

          多個(gè)@synchronized() 嵌套,沒(méi)有意義也不會(huì)報(bào)錯(cuò);是objc中提供的同步鎖,支持遞歸。但是在swift中刪除了,可以使用objc_sync替代。

          讀完本文你可以了解到synchronized的實(shí)現(xiàn)原理

          我們今天重點(diǎn)討論一下下面幾個(gè)問(wèn)題

          1. synchronized 的 obj 為 nil 會(huì)怎么樣
          2. synchronized 會(huì)影響obj嗎
          3. synchronized 和 pthread_mutex 以及objc_sync 的關(guān)系

          我們驗(yàn)證一下嵌套

          創(chuàng)建一個(gè)Person類(lèi),里面一個(gè)run方法

          - (void)run {
              @synchronized (self) {
                  NSLog(@"s1");
                  @synchronized (self) {
                      NSLog(@"s2");
                  }
              }
          }

          執(zhí)行之后發(fā)現(xiàn)都是正常打印

          swift和OC分別實(shí)現(xiàn)方式

          ///objc
          @synchronized(self) {
              //action
          }

          ///swift
          objc_sync_enter(self)
          //action
          objc_sync_exit(self)

          生成runtime代碼查看底層實(shí)現(xiàn)

          Person類(lèi)改為如下內(nèi)容

          - (void)run {
              @synchronized (self) {
                  NSLog(@"s1");
              }
          }

          然后將Person轉(zhuǎn)為C++代碼 clang -x objective-c -rewrite-objc Person.m

          打開(kāi)Person.cpp文件找到以下c++的代碼

          static void _I_Person_run(Person * self, SEL _cmd) {
              { id _rethrow = 0; id _sync_obj = (id)self; objc_sync_enter(_sync_obj);
                  try {
                      struct _SYNC_EXIT { _SYNC_EXIT(id arg) : sync_exit(arg) {}
                          ~_SYNC_EXIT() {objc_sync_exit(sync_exit);}
                          id sync_exit;
                      } _sync_exit(_sync_obj);
                      
                      NSLog((NSString *)&__NSConstantStringImpl__var_folders_1m_kzn6dnx501b1x94s5bwpxjrw0000gn_T_Person_e7a30b_mi_0);
                      { id _rethrow = 0; id _sync_obj = (id)self; objc_sync_enter(_sync_obj);
                          try {
                              struct _SYNC_EXIT { _SYNC_EXIT(id arg) : sync_exit(arg) {}
                                  ~_SYNC_EXIT() {objc_sync_exit(sync_exit);}
                                  id sync_exit;
                              } _sync_exit(_sync_obj);
                              
                              NSLog((NSString *)&__NSConstantStringImpl__var_folders_1m_kzn6dnx501b1x94s5bwpxjrw0000gn_T_Person_e7a30b_mi_1);
                          } catch (id e) {_rethrow = e;}
                          { struct _FIN { _FIN(id reth) : rethrow(reth) {}
                              ~_FIN() { if (rethrow) objc_exception_throw(rethrow); }
                              id rethrow;
                          } _fin_force_rethow(_rethrow);}
                      }
                      
                  } catch (id e) {_rethrow = e;}
                  { struct _FIN { _FIN(id reth) : rethrow(reth) {}
                      ~_FIN() { if (rethrow) objc_exception_throw(rethrow); }
                      id rethrow;
                  } _fin_force_rethow(_rethrow);}
              }
          }

          synchronized調(diào)用了try catch,內(nèi)部調(diào)用了objc_sync_enter和objc_sync_exit。這兩個(gè)函數(shù)又是如何實(shí)現(xiàn)的呢?

          objc_sync_enter & objc_sync_exit

          我們翻閱objc4源碼,在objc-sync.mm文件中,找到了具體實(shí)現(xiàn)

          // Begin synchronizing on 'obj'
          // Allocates recursive mutex associated with 'obj' if needed.
          // Returns OBJC_SYNC_SUCCESS once lock is acquired.  
          int objc_sync_enter(id obj)
          {
              int result = OBJC_SYNC_SUCCESS;

              if (obj) {
                  SyncData* data = id2data(obj, ACQUIRE);
                  assert(data);
                  data->mutex.lock();
              } else {
                  // @synchronized(nil) does nothing
                  if (DebugNilSync) {
                      _objc_inform("NIL SYNC DEBUG: @synchronized(nil); set a breakpoint on objc_sync_nil to debug");
                  }
                  objc_sync_nil();
              }

              return result;
          }
          // End synchronizing on 'obj'
          // Returns OBJC_SYNC_SUCCESS or OBJC_SYNC_NOT_OWNING_THREAD_ERROR
          int objc_sync_exit(id obj)
          {
              int result = OBJC_SYNC_SUCCESS;
              
              if (obj) {
                  SyncData* data = id2data(obj, RELEASE); 
                  if (!data) {
                      result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
                  } else {
                      bool okay = data->mutex.tryUnlock();
                      if (!okay) {
                          result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
                      }
                  }
              } else {
                  // @synchronized(nil) does nothing
              }
           

              return result;
          }

          仔細(xì)看objc_sync_enter這段源碼和注釋?zhuān)芮宄枋隽诉@個(gè)函數(shù)的作用:1.在obj上開(kāi)始同步鎖 2.obj為nil,加鎖不會(huì)成功 3.obj不是nil,初始化遞歸互斥鎖(recursive mutex),并關(guān)聯(lián)obj

          objc_sync_enter的加鎖方式

          從底層源碼我們看到加鎖方式是先獲取obj關(guān)聯(lián)的同步數(shù)據(jù)SyncData,然后加鎖

          SyncData同步數(shù)據(jù)是什么?

          //objc-sync.mm
          typedef struct SyncData {
               //下一條同步數(shù)據(jù)
              struct SyncData* nextData;
              //鎖的對(duì)象
              DisguisedPtr<objc_object> object;
              //等待的線程數(shù)量
              int32_t threadCount;  // number of THREADS using this block
              //互斥遞歸鎖
              recursive_mutex_t mutex;
          } SyncData;

          SyncData是一個(gè)結(jié)構(gòu)體,類(lèi)似鏈表

          nextData:SyncData的指針節(jié)點(diǎn),指向下一條數(shù)據(jù) object:鎖住的對(duì)象 threadCount:等待的線程數(shù)量 mutex:使用的遞歸互斥鎖

          遞歸互斥鎖recursive_mutex_t具體實(shí)現(xiàn)

          recursive_mutex_t是基于pthread_mutex_t的封裝。打開(kāi)objc-os.h找到具體實(shí)現(xiàn)

          //objc-os.h
          using recursive_mutex_t = recursive_mutex_tt<DEBUG>;
          class recursive_mutex_tt : nocopy_t {
              pthread_mutex_t mLock;

            public:
              recursive_mutex_tt() : mLock(PTHREAD_RECURSIVE_MUTEX_INITIALIZER) { }
              void lock() {
                  lockdebug_recursive_mutex_lock(this);
                  int err = pthread_mutex_lock(&mLock);
                  if (err) _objc_fatal("pthread_mutex_lock failed (%d)", err);
              }
              //這里省略......
          }

          synchronized的原理

          內(nèi)部為每一個(gè)obj分配一把recursive_mutex遞歸互斥鎖。針對(duì)每個(gè)obj,通過(guò)這個(gè)recursive_mutex遞歸互斥鎖進(jìn)行加鎖、解鎖

          內(nèi)部是如何管理obj和recursive_mutex的

          這里就不一一深究了,有興趣的可以繼續(xù)看源碼

          結(jié)論

          1. synchronized 的 obj 為 nil 怎么辦?加鎖操作無(wú)效。
          2. synchronized 會(huì)對(duì) obj 做什么操作嗎?會(huì)為obj生成遞歸自旋鎖,并建立關(guān)聯(lián),生成 SyncData,存儲(chǔ)在當(dāng)前線程的緩存里或者全局哈希表里。
          3. synchronized 和 pthread_mutex 有什么關(guān)系?SyncData里的遞歸互斥鎖,使用 pthread_mutex 實(shí)現(xiàn)的。
          4. synchronized 和 objc_sync 有什么關(guān)系?synchronized 底層調(diào)用了 objc_sync_enter() 和 objc_sync_exit()

          作者:自如大前端研發(fā)中心-李長(zhǎng)鴻

          https://juejin.cn/post/7017703842594684935


          -End-

          最近有一些小伙伴,讓我?guī)兔φ乙恍?nbsp;面試題 資料,于是我翻遍了收藏的 5T 資料后,匯總整理出來(lái),可以說(shuō)是程序員面試必備!所有資料都整理到網(wǎng)盤(pán)了,歡迎下載!

          點(diǎn)擊??卡片,關(guān)注后回復(fù)【面試題】即可獲取

          在看點(diǎn)這里好文分享給更多人↓↓

          瀏覽 38
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  午夜福利视频在线 | z三级片精品播放 | 香蕉插逼| 青娱乐超碰在线 | 二区在线视频 |