iOS 多線程(線程的生命週期)

多線程的基本概念

進程的定義

  • 進程(Process)是計算機中的程序關於某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位,是操做系統結構的基礎。在早期面向進程設計的計算機結構中,進程是程序的基本執行實體;在當代面向線程設計的計算機結構中,進程是線程的容器。程序是指令、數據及其組織形式的描述,進程是程序的實體。
  • 進程是指在系統中正在運行的一個應用程序
  • 每一個進程相互是獨立的,每一個進程均運行在其專用的且受保護的內存

線程的定義

  • 線程(英語:thread)是操做系統可以進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運做單位。一條線程指的是進程中一個單一順序的控制流,一個進程中能夠併發多個線程,每條線程並行執行不一樣的任務。在Unix System V及SunOS中也被稱爲輕量進程(lightweight processes),但輕量進程更多指內核線程(kernel thread),而把用戶線程(user thread)稱爲線程。
  • 在同一進程中的各個線程,均可以共享該進程所擁有的資源,這首先表如今:全部線程都具備相同的地址空間(進程的地址空間),這意味着,線程能夠訪問該地址空間的每個虛地址;此外,還能夠訪問進程所擁有的已打開文件、定時器、信號量機構等。因爲同一個進程內的線程共享內存和文件,因此線程之間互相通訊沒必要調用內核。
  • 線程是進程的基本執行單位,一個進程的全部任務都在線程中執行
  • 進程要想執行任務,必須得有線程,進程至少要有一條線程
  • 程序啓動會默認開啓一條線程,這條線程被稱爲主線程或UI線程

進程與線程的關係

  • 地址空間:同一進程的線程共享本進程的地址空間,而進程之間則是獨立的地址空間
  • 資源擁有:同一進程內的線程共享本進程的資源如內存、I/O、cpu等,可是進程之間的資源是獨立的。
  • 一個進程崩潰後,在保護模式下不會對其餘進程產生影響,可是一個線程崩潰整個進程都死掉。因此多進程要比多線程健壯。
  • 進程切換時,消耗的資源大,效率高。因此涉及到頻繁的切換時,使用線程要好於進程。一樣若是要求同時進行而且又要共享某些變量的併發操做,只能用線程不能用進程
  • 執行過程:每一個獨立的進程有一個程序運行的入口、順序執行序列和程序入口。可是線程不能獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制。
  • 線程是處理器調度的基本單位,可是進程不是。
  • 二者都可併發執行。

多線程的意義

  • 優勢
    • 使用線程能夠把佔據時間長的程序中的任務放到後臺去處理
    • 用戶界面能夠更加吸引人,這樣好比用戶點擊了一個按鈕去觸發某些事件的處理,能夠彈出一個進度條來顯示處理的進度
    • 程序的運行速度可能加快
    • 在一些等待的任務實現上如用戶輸入、文件讀寫和網絡收發數據等,線程就比較有用了。在這種狀況下能夠釋放一些珍貴的資源如內存佔用等等。
  • 缺點
    • 建立子線程是有開銷的,iOS下主要成本包括:內核數據結構(大約1KB)、棧空間(子線程512K、主線程1MB,也可使用-setStackSize:設置,但必須是4K的倍數,並且最小是16K),建立線程大約須要90毫秒的建立時間
    • 若是開啓大量線程,會下降程序的性能
    • 線程越多,CPU在調度線程的開銷就越大
    • 程序設計更加複雜:好比線程之間的通訊、多線程的數據共享

多線程的原理

  • 同一時間,CPU只能處理一條線程,只有一條線程在工做(執行)
  • 多線程併發(同時)執行,其實就是CPU執行快速地在多條線程之間調度(切換)
  • 下圖是多線程的圖解,CPU在線程一、線程二、線程三、線程4中不斷的切換,這樣就能夠達到一個併發的效果

多線程的生命週期

線程的生命週期是:新建 - 就緒 - 運行 - 阻塞 - 死亡程序員

  • 新建:實例化線程對象
  • 就緒:向線程對象發送start消息,線程對象被加入可調度線程池等待CPU調度。
  • 運行:CPU 負責調度可調度線程池中線程的執行。線程執行完成以前,狀態可能會在就緒和運行之間來回切換。就緒和運行之間的狀態變化由CPU負責,程序員不能干預。
  • 阻塞:當知足某個預約條件時,可使用休眠或鎖,阻塞線程執行。sleepForTimeInterval(休眠指定時長),sleepUntilDate(休眠到指定日期),@synchronized(self):(互斥鎖)。
  • 死亡:正常死亡,線程執行完畢。非正常死亡,當知足某個條件後,在線程內部停止執行/在主線程停止線程對象

還有線程的exit和cancel [NSThread exit]:一旦強行終止線程,後續的全部代碼都不會被執行。
[thread cancel]取消:並不會直接取消線程,只是給線程對象添加 isCancelled 標記。算法

下圖表示線程的生命週期 編程

線程的執行流程以下:

  • 新建 - 就緒(在可調度線程池中,等待被CPU的調度執行) - 運行
  • 運行 - CPU切換到其餘的線程 - 就緒
  • 運行 - 調用的sleep方法 - 阻塞 - sleep的時間到了 - 就緒
  • 運行 - 任務執行完成 - 死亡
  • 運行 - exit - 死亡

線程加入到可調度線程池過程 安全

多線程實現方案

iOS中實現多線程的方案有如下四種 bash

pthread 開啓線程

pthread_t tid;
int tret = pthread_create(&tid, NULL, thread_run, NULL);
複製代碼

NSThread 開啓線程網絡

//繼承自NSObject的類的對象 均可以調用這個方法 只不過拿不到線程對象
[self performSelectorInBackground:@selector(NSThreadDemo:) withObject:@"NSObjectCategory"];

// 經過類方法建立 分離出來一個線程 不須要手動開啓線程  自動開啓線程而且執行方法
[NSThread detachNewThreadSelector:@selector(NSThreadDemo:) toTarget:self withObject:@"classMethodThread"];

// 經過對象方法來建立線程 而且須要手動啓動線程
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(NSThreadDemo:) object:@"objectMethodThread"];
//手動啓動線程
[thread start];
複製代碼

GCD 開啓線程數據結構

// 串行隊列的建立方法
dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_SERIAL);

// 併發隊列的建立方法
dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_CONCURRENT);

// 同步執行任務建立方法
dispatch_sync(queue, ^{
    // 這裏放同步執行任務代碼
});

// 異步執行任務建立方法
dispatch_async(queue, ^{
    // 這裏放異步執行任務代碼
});
複製代碼

NSOperation 開啓線程多線程

//NSInvocationOperation   封裝操做
NSInvocationOperation *operation=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test) object:nil];

//執行操做
[operation start];

//建立NSBlockOperation操做對象
NSBlockOperation *operation=[NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"NSBlockOperation------%@",[NSThread currentThread]);
}];

//添加操做
[operation addExecutionBlock:^{
    NSLog(@"NSBlockOperation1------%@",[NSThread currentThread]);
}];

[operation addExecutionBlock:^{
    NSLog(@"NSBlockOperation2------%@",[NSThread currentThread]);
}];

//開啓執行操做
[operation start];
複製代碼

iOS 中的鎖

鎖的概念定義併發

  • 臨界區:指的是一塊對公共資源進行訪問的代碼,並不是一種機制或是算法。
  • 自旋鎖:是用於多線程同步的一種鎖,線程反覆檢查鎖變量是否可用。因爲線程在這一過程當中保持執行,所以是一種忙等待。一旦獲取了自旋鎖,線程會一直保持該鎖,直至顯式釋放自旋鎖。自旋鎖避免了進程上下文的調度開銷,所以對於線程只會阻塞很短期的場合是有效的。
  • 互斥鎖(Mutex):是一種用於多線程編程中,防止兩條線程同時對同一公共資源(好比全局變量)進行讀寫的機制。該目的經過將代碼切片成一個一個的臨界區而達成。
  • 讀寫鎖:是計算機程序的併發控制的一種同步機制,也稱「共享-互斥鎖」、「多讀者-單寫者鎖」,用於解決多線程對公共資源讀寫問題。讀操做可併發重入,寫操做是互斥的。讀寫鎖一般用互斥鎖、條件變量、信號量實現。
  • 信號量(semaphore):是一種更高級的同步機制,互斥鎖能夠說是semaphore在僅取值0/1時的特例。信號量能夠有更多的取值空間,用來實現更加複雜的同步,而不僅僅是線程間互斥。
  • 條件鎖:就是條件變量,當進程的某些資源要求不知足時就進入休眠,也就是鎖住了。當資源被分配到了,條件鎖打開,進程繼續運行。

性能比較 框架

互斥鎖

  • NSLock:是Foundation框架中以對象形式暴露給開發者的一種鎖,(Foundation框架同時提供了NSConditionLock,NSRecursiveLock,NSCondition)NSLock定義如圖,tryLock 和 lock 方法都會請求加鎖,惟一不一樣的是trylock在沒有得到鎖的時候能夠繼續作一些任務和處理。lockBeforeDate方法也比較簡單,就是在limit時間點以前得到鎖,沒有拿到返回NO。
  • pthread_mutex:實際運用項目以下
  • @synchronize:實際項目中:AFNetworking中 isNetworkActivityOccurring屬性的getter方法

參考文章

iOS多線程全套:線程生命週期,多線程的四種解決方案,線程安全問題,GCD的使用,NSOperation的使用

相關文章
相關標籤/搜索