多線程原理| 8月更文挑戰

進程是什麼

進程是指在系統中正在運行的一個應用程序(App);每一個進程之間是獨立的,每一個進程均運行在其專用的且受保護的內存空間中;經過活動監視器能夠查看Mac系統中所開啓的進程。 ​markdown

線程是什麼

線程是進程的基本執行單元,一個進程的全部任務都是在線程中執行;進程想要執行任務必讀得有線程,進程至少有一條線程。程序啓動後會默認開啓一條線程,這條線程被稱做主線程或者UI線程。 ​多線程

進程與線程的關係

地址空間:同⼀進程的線程共享本進程的地址空間,⽽進程之間則是獨⽴的地址空間。 資源擁有:同⼀進程內的線程共享本進程的資源如內存、I/O、cpu等,可是進程之間的資源是獨⽴的。併發

  1. ⼀個進程崩潰後,在保護模式下不會對其餘進程產⽣影響,可是⼀個線程崩潰整個進程都死掉。因此多進程要⽐多線程健壯。
  2. 進程切換時,消耗的資源⼤,效率⾼。因此涉及到頻繁的切換時,使⽤線程要好於進程。一樣若是要求同時進⾏而且⼜要共享某些變量的併發操做,只能⽤線程不能⽤進程
  3. 執⾏過程:每一個獨⽴的進程有⼀個程序運⾏的⼊⼝、順序執⾏序列和程序⼊⼝。可是線程不能獨⽴執⾏,必須依存在應⽤程序中,由應⽤程序提供多個線程執⾏控制。
  4. 線程是處理器調度的基本單位,可是進程不是。
  5. 線程沒有地址空間,線程包含在進程地址空間中
  6. 線程局部存儲(ThreadLocalStorage,TLS)。線程局部存儲是某些操做系統爲線程單獨提供的私有空間,但一般只具備頗有限的容量。(獲取同步鎖的時候用到sync_data/在objc_init函數中也存在)

多線程的意義

多線程並非真正原理上的併發,只是CPU在多個任務直接進⾏快速的切換,這個時間間隔就是時間⽚。真正的併發創建在一個多核的基礎上函數

優勢:oop

  1. 能適當提升程序的執行效率
  2. 能適當提升資源的利用率(cpu 內存)
  3. 線程上的任務執行完成後,線程會自動銷燬

缺點:性能

  1. 開啓線程須要佔用必定的內存空間(默認狀況下,每個線程都佔512kb)
  2. 若是開啓大量的線程,會佔用大量的內存空間,下降程序的性能
  3. 線程越多,CPU在調用線程上的開銷就越大
  4. 程序設計的更加複雜好比線程之間的通訊、多線程的數據共享

單核同一時間,cpu只能處理一個線程,換言之,同一時間只有1個線程在執行 多線程同時執行實際上是cpu快速的在多個線程之間的切換;cpu線程調度的時間足夠快,就形成了多線程的同時執行的假象。 若是線程數量很是多的話,cpu會在N個線程之間切換,消耗大量的cpu資源,每一個線程被調度的次數會下降,線程的執行效率下降。 ​ui

多線程的幾種方案

image.png

線程生命週期

線程的生命週期.png

線程調度的策略

線程池.png

飽和策略

  1. AbortPolicy 直接拋出RejectedExecutionExeception異常來阻⽌系統正常運⾏
  2. CallerRunsPolicy 將任務回退到調⽤者
  3. DisOldestPolicy 丟掉等待最久的任務
  4. DisCardPolicy 直接丟棄任務

任務執行速度的影響因素

  1. cpu
  2. 任務的優先級
  3. 任務的複雜度
  4. 線程當前的狀態

優先級翻轉

  1. IO密集型 :頻繁等待
  2. CPU密集型 :不多等待

爲了不出現餓死狀態,cpu調度 IO密集型會提升優先級atom

改變線程優先級的因素

  1. 用戶指定優先級
  2. 根據等待的頻繁度
  3. 長時間不執行的任務也會提升優先級

自旋鎖和互斥鎖

  • 互斥鎖 發現其餘線程執行 當前線程 休眠 (就緒狀態) 一直在等打開 喚醒執行
  • 自旋鎖 發現其餘線程執行 當前線程 詢問 - 忙等 耗費性能比較高 通常使用在短小的任務中

atomic :是原子屬性,是爲多線程開發準備的,是默認屬性!僅僅在屬性的 setter方法中,增長了鎖(自旋鎖),可以保證同一時間,只有一條線程對屬性進行操做。可是同一個時間多個線程均可以取值 nonatomic 是非原子屬性。沒有鎖!性能高!spa

看源碼:操作系統

void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy) 
{
    bool copy = (shouldCopy && shouldCopy != MUTABLE_COPY);
    bool mutableCopy = (shouldCopy == MUTABLE_COPY);
    reallySetProperty(self, _cmd, newValue, offset, atomic, copy, mutableCopy);
}

複製代碼
static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
  	 //....
    if (!atomic) {
        oldValue = *slot;
        *slot = newValue;
    } else {
        spinlock_t& slotlock = PropertyLocks[slot];
        slotlock.lock();
        oldValue = *slot;
        *slot = newValue;        
        slotlock.unlock();
    }
}
複製代碼

從上面咱們能夠看出atomic不是鎖,只是一個加鎖的標識。 ​

線程和Runloop

  1. runloop與線程是⼀⼀對應的,⼀個runloop對應⼀個核⼼的線程,爲何說是核⼼的,是由於runloop是能夠嵌套的,可是核⼼的只能有⼀個,他們的關係保存在⼀個全局的字典⾥。
  2. runloop是來管理線程的,當線程的runloop被開啓後,線程會在執⾏完任務後進⼊休眠狀態,有了任務就會被喚醒去執⾏任務。
  3. runloop在第⼀次獲取時被建立,在線程結束時被銷燬。
  4. 對於主線程來講,runloop在程序⼀啓動就默認建立好了。
  5. 對於⼦線程來講,runloop是懶加載的,只有當咱們使⽤的時候纔會建立,因此在⼦線程⽤定時器要注意:確保⼦線程的runloop被建立,否則定時器不會回調。

補充

__bridge只作類型轉換,可是不修改對象(內存)管理權; __bridge_retained將oc對象轉換爲CoreFoundation,內存管理權限交給咱們,後續須要使用CFRealeas或者相關的方法來釋放對象 __bridge_transferCoreFoundation轉換爲oc對象,同時將內存的管理權限交回給ARC

相關文章
相關標籤/搜索