iOS開發之多線程技術

来源:http://www.cnblogs.com/Jepson1218/archive/2016/02/03/5180196.html
-Advertisement-
Play Games

本篇爭取一篇講清講透,依然將通過四大方面清晰的對iOS開發中多線程的用法進行詳盡的講解: 一、什麼是多線程 1)多線程執行原理 2)線程與進程 3)多線程的優缺點 二、我們為什麼要用多線程編程技術 三、如何使用多線程技術 1)pthread技術 2)NSThread技術 2.1)線程屬性 2.2)資


本篇爭取一篇講清講透,依然將通過四大方面清晰的對iOS開發中多線程的用法進行詳盡的講解:

一、什麼是多線程

  1)多線程執行原理

  2)線程與進程

  3)多線程的優缺點

二、我們為什麼要用多線程編程技術

三、如何使用多線程技術

1)pthread技術

2)NSThread技術

2.1)線程屬性

2.2)資源共用(搶奪)

3)GCD技術

4) NSOperation技術

四、線程的生命周期(線程狀態)

 


一、什麼是多線程

  多線程(英語:multithreading),是指從軟體或者硬體上實現多個線程併發執行的技術。具有多線程能力的電腦因有硬體支持而能夠在同一時間執行多於一個線程,進而提升整體處理性能。具有這種能力的系統包括對稱多處理機、多核心處理器以及晶元級多處理(Chip-level multithreading)或同時多線程(Simultaneous multithreading)處理器。在一個程式中,這些獨立運行的程式片段叫作“線程”(Thread),利用它編程的概念就叫作“多線程處理(Multithreading)”。具有多線程能力的電腦因有硬體支持而能夠在同一時間執行多於一個線程(臺灣譯作“執行緒”),進而提升整體處理性能。

  1) 多線程執行原理

  

  a. (單核CPU)同一時間,cpu只能處理1個線程,只有1個線程在執行

  b. 多線程同時執行:是CPU快速的在多個線程之間的切換

  c. cpu調度線程的時間足夠快,就造成了多線程的"同時"執行

  d. 如果線程數非常多,cpu會在n個線程之間切換,消耗大量的cpu資源

  i. 每個線程被調度的次數會降低,線程的執行效率降低

  2)線程與進程

  每個正在系統上運行的程式都是一個進程。每個進程包含一到多個線程。進程也可能是整個程式或者是部分程式的動態執行。線程是一組執行的集合,或者是程式的特殊段,它可以在程式里獨立執行。也可以把它理解為代碼運行的上下文。所以線程基本上是輕量級的進程,它負責在單個程式里執行多任務。通常由操作系統負責多個線程的調度和執行。

  線程是程式中一個單一的順序控制流程,在單個程式中同時運行多個線程完成不同的工作,稱為多線程。

  線程和進程的區別在於,子進程和父進程有不同的代碼和數據空間,而多個線程則共用數據空間,每個線程有自己的執行堆棧和程式計數器為其執行上下文,多線程主要是為了節約CPU時間,發揮利用,根據具體情況而定。線程的運行中需要使用電腦的記憶體資源和CPU。  

  3)多線程的優缺點

  優點:

    1、使用線程可以把占據時間長的程式中的任務放到後臺去處理。

    2、用戶界面可以更加吸引人,這樣比如用戶點擊了一個按鈕去觸發某些事件的處理,可以彈出一個進度條來顯示處理的進度。  

    3、程式的運行速度可能加快。

    4、在一些等待的任務實現上如用戶輸入、文件讀寫和網路收發數據等,線程就比較有用了。在這種情況下可以釋放一些珍貴的資源如記憶體占用等等。

    5、線程上的任務執行完成後,線程會自動銷毀。

  缺點:

    1、線程越多,cpu在調用線程上的開銷就越大,如果有大量的線程,會影響性能,因為操作系統需要在它們之間切換。

    2、開啟線程需要占用一定的記憶體空間(預設情況下,每一個線程都占512KB),如果開啟大量的線程,會占用大量的記憶體空間,降低程式的性能,更多的線程需要更多的記憶體空間。

    3、程式設計更加複雜,比如線程間的通信、多線程的數據共用,可能會給程式帶來更多的BUG,因此要小心使用。

    4、線程的中止需要考慮其對程式運行的影響。

    5、通常塊模型數據是在多個線程間共用的,需要一個合適的鎖系統替換掉數據共用。

  

  註意:iOS 8.0後主線程的預設堆棧大小也是 512K,官方文檔標註錯誤。

 


二、我們為什麼要用多線程編程技術

  在大多數研究領域內是要求線程調度程式要能夠快速選擇其中一個已就緒線程去運行,而不是一個一個運行而降低效率。所以要讓調度程式去分辨線程的優先順序是很重要的。在移動開發過程中,一切均已用戶體驗作為首要任務,這時多線程的重要性不言而喻。

  一個程式運行後,預設會開啟1個線程,稱為“主線程”或“UI線程”,主線程一般用來刷新UI界面,處理UI事件(比如:點擊、滾動、拖拽等事件)

  主線程使用註意

    別將耗時的操作放到主線程中

    耗時操作會卡住主線程,嚴重影響UI的流暢度,給用戶一種卡的壞體驗

 


三、如何使用多線程技術

ios中多線程實現的多種技術方案:

POSIX 表示可移植操作系統介面(Portable Operating System Interface )-----pthread

 

1)pthread技術:

pthread 是 POSIX 多線程開發框架,由於是跨平臺的 C 語言框架,在蘋果的頭文件中並沒有詳細的註釋要查閱 pthread 有關資料,可以訪問 http://baike.baidu.com

// 創建線程,並且線上程中執行 demo 函數
- (void)pthreadDemo {

    /**
     參數:
     1> 指向線程標識符的指針,C 語言中類型的結尾通常 _t/Ref,而且不需要使用 *
     2> 用來設置線程屬性
     3> 新建立的線程執行代碼的函數
     4> 運行函數的參數

     返回值:
     - 若線程創建成功,則返回0
     - 若線程創建失敗,則返回出錯編號

     在混合開發時,如果在 C 和 OC 之間傳遞數據,需要使用 __bridge 進行橋接,橋接的目的就是為了告訴編譯器如何管理記憶體
     */
    pthread_t threadId = NULL;
    NSString *str = @"Hello Pthread";

    int result = pthread_create(&threadId, NULL, demo, (__bridge void *)(str));

    result ? NSLog(@"為其他任何值時代表開闢子線程失敗") : NSLog(@"當result為0時表示開闢子線程成功");
}

// 後臺線程調用函數
void *demo(void *params) {
    NSString *str = (__bridge NSString *)(params);

    NSLog(@"%@ - %@", [NSThread currentThread], str);

    return NULL;
}
C語言中pthread.h里pthread實現多線程

 

2)NSThread技術:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSLog(@"主線程%@", [NSThread currentThread]);
    /**
     多個線程之間的執行順序是隨機的
     */
    
    // 方式1:通過NSThread的對象方法
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(demo:) object:@"方式1"];
    [thread start];
    
    // 方式2:沒有thread字眼,隱式創建並啟動線程,所有 NSObject 都可以使用此方法,在其他線程執行方法
    [self performSelectorInBackground:@selector(demo:) withObject:@"方式2"];
    
    // 方式3:detachNewThreadSelector 類方法不需要啟動,會自動創建線程並執行 @selector 方法
    [NSThread detachNewThreadSelector:@selector(demo:) toTarget:self withObject:@"方式3"];
    
}

- (void)demo:(NSString *)str {
    NSLog(@"%@, %@", str, [NSThread currentThread]);
}
通過NSThread創建線程的三種方式

 

2.1)線程屬性

1. name - 線程名稱
2. threadPriority - 線程優先順序
  取值範圍從 0~1.0
  1.0表示優先順序最高
  0.0表示優先順序最低
  預設優先順序是0.5
3. stackSize - 棧區大小
4. isMainThread - 是否主線程

 

2.2)資源共用(搶奪)

  1塊資源可能會被多個線程共用,也就是多個線程可能會訪問同一塊資源,比如多個線程訪問同一個對象、同一個變數、同一個文件當多個線程訪問同一塊資源時,很容易引發數據錯亂和數據安全問題。如購買火車票問題:

  解決方案:

#pragma mark
#pragma mark - 模擬賣票系統
- (void)sellTicket {
    
    _count = 50;
    
    NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(ticket) object:nil];
    thread1.name = @"t1";
    [thread1 start];
    
    NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(ticket) object:nil];
    thread2.name = @"t2";
    [thread2 start];
}

- (void)ticket {
    
    while (YES) {
        
        // 被加鎖的對象
        @synchronized(self) {
            if (_count > 0) {
                _count = self.count - 1;
                NSLog(@"剩餘票數%ld ——%@", _count, [NSThread currentThread]);
            } else {
                NSLog(@"票賣沒了倒霉蛋");
                break;
            }
        }
    }
    
}
賣票系統線程同步解決線程不安全問題

 

  • 互斥鎖:如果發現有其他線程正在執行鎖定的代碼,線程會進入休眠狀態,等待其他線程執行完畢,打開鎖之後,線程會被喚醒
  • 自旋鎖:如果發現有其他線程正在執行鎖定的代碼,線程會以死迴圈的方式,一直等待鎖定代碼執行完成

  線程安全

多個線程進行讀寫操作時,仍然能夠得到正確結果,被稱為線程安全,要實現線程安全,必須要用到鎖、
為了得到更佳的用戶體驗,UIKit 不是線程安全的,所以更新 UI 的操作都必須主線程上執行!因此,主線程又被稱為UI 線程。

 

3)GCD技術

  為保證篇幅不過與雜糅,請見“IOS開發之多線程技術——GCD篇

   

4) NSOperation技術

  為保證篇幅不過與雜糅,請見“IOS開發之多線程技術——NSOperation篇

 


四、線程的生命周期(線程狀態)

新建

  實例化線程對象

就緒

  - (void)start;

  向線程對象發送 start 消息,線程對象被加入 可調度線程池 等待 CPU 調度
  detachNewThreadSelector 方法和 performSelectorInBackground 方法會直接實例化一個線程對象並加入 可調度線程池
運行
  CPU 負責調度可調度線程池中線程的執行
  線程執行完成之前(死亡之前),狀態可能會在就緒和運行之間來回切換
  就緒和運行之間的狀態變化由 CPU 負責,程式員不能幹預
阻塞
  當滿足某個預定條件時,可以使用休眠或鎖阻塞線程執行

  + (void)sleepUntilDate:(NSDate *)date;

  + (void)sleepForTimeInterval:(NSTimeInterval)ti;

  @synchronized(self):互斥鎖
死亡:+ (void)exit

  正常死亡
  線程執行完畢
  非正常死亡
  當滿足某個條件後,線上程內部自己中止執行(自殺),[NSThread exit];
  當滿足某個條件後,在主線程給其它線程打個死亡標記(下聖旨),讓子線程自行了斷.(被逼著死亡)

  註意:在終止線程之前,應該註意釋放之前分配的對象!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • $.extend()和$.fn.extend()函數用法簡單介紹:標題中的兩個方法在jQuery插件開發中非常的重要,下麵通過簡單的代碼實例介紹一下它們的用法。本章節不會介紹它的原理,而是只給出它們的作用是什麼,能夠做什麼事情。jQuery.extend()可以為jQuery類添加新的方法,類似於c
  • javascript如何設置指定標簽的透明度:在實際應用中,可能需要動態的設置標簽的透明度,現在就以div為例子介紹一下如何實現此效果。代碼實例如下: <!DOCTYPE html> <html> <head> <meta charset=" utf-8"> <meta name="author"
  • body在預設情況下是具有margin外邊距的:這裡只是陳述一個事實,那就是body具有外邊距在預設情況下。代碼實例如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="author" content="http:/
  • 本篇將從四個方面對iOS開發中使用到的NSOperation技術進行講解: 一、什麼是NSOperation 二、我們為什麼使用NSOperation 三、在實際開發中如何使用NSOperation 1、自定義NSOperation 2、NSOperation的基本使用 3、NSOperation實
  • 分類:C#、Android; 日期:2016-02-04 3.5 示例5--多地圖展示 一、簡介 地圖控制項自v2.3.5版本起,支持多實例,即開發者可以在一個頁面中建立多個地圖對象,並且針對這些對象分別操作且不會產生相互干擾。 文件名:Demo04MultiMapView.cs 簡介:介紹多MapV
  • 本篇將從四個方面對iOS開發中GCD的使用進行詳盡的講解: 一、什麼是GCD 二、我們為什麼要用GCD技術 三、在實際開發中如何使用GCD更好的實現我們的需求 一、Synchronous & Asynchronous 同步 & 非同步 二、Serial Queues & Concurrent Queu
  • Android編譯過程中遇到的難題及解決方案。
  • UIViewAutoresizingNone = 0, UIViewAutoresizingFlexibleLeftMargin = 1 << 0, UIViewAutoresizingFlexibleWidth = 1 << 1, UIViewAutoresizingFlexibleRightMa
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...