玩轉iOS開發:iOS中的NSThread開發

文章分享至個人我的技術博客: cainrun.github.io/15020181423…html


前面咱們已經把經常使用的GCD, NSOperation, NSOperationQueue講完了, 如今咱們繼續來看看, 另外一個不經常使用的多線程(實際上是我本身不經常使用), 它就是NSThread.git

說到NSThread的話, 我麼那就不得不提到它的底層叫作Pthread, 這是一個由C語言寫的多線程技術, 能夠在Unix, LinuxWindows上使用.github

但因爲是用C語言所寫的, 因此須要本身管理線程生命週期, 開發難度比較大(不得不佩服一下搞C語言的大佬們), 這裏咱們簡單瞭解一下就行了, 想深刻了解的話, 能夠自行去谷歌一下.vim

轉載聲明:如須要轉載該文章, 請聯繫做者, 而且註明出處, 以及不能擅自修改本文.安全


Pthread的介紹

這裏引用一段來自維基百科Pthread介紹:微信

POSIX線程(英語:POSIX Threads,常被縮寫爲Pthreads)是POSIX的線程標準,定義了建立和操縱線程的一套API多線程

實現POSIX線程標準的庫常被稱做Pthreads,通常用於Unix-like POSIX系統,如LinuxSolaris框架

可是Microsoft Windows上的實現也存在,例如直接使用Windows API實現的第三方庫pthreads-w32函數

而利用WindowsSFU/SUA子系統,則可使用微軟提供的一部分原生POSIX API性能


Pthread的使用

在舉例子🌰以前, 咱們得分析一下使用Pthread的幾個步驟:

  • 首先要引入頭文件#import <pthread.h>
  • 其次要建立線程,並開啓線程執行任務
- (void)cratePthread {

    pthread_t thread;

    pthread_create(&thread, NULL, run, NULL);
}

void *run(void *param) {

    NSLog(@"執行任務, 當前的線程爲: %@", [NSThread currentThread]);

    return NULL;
}複製代碼
2017-08-06 20:33:42.496 NSThread-Example[4008:314745] 執行任務, 當前的線程爲: <NSThread: 0x60800007cb40>{number = 3, name = (null)}複製代碼

這裏要解釋一下pthread_create(&thread, NULL, run, NULL)括號裏的四個屬性:

  • 第一個是線程對象, 通常是用&號加線程對象名.
  • 第二個和第四個是能夠給線程添加屬性.
  • 第三個表示的是, 指向函數的指針, 代碼中的run其實就是咱們以前講到的任務.

NSThread的介紹

NSThread是蘋果爸爸針對Pthread而封裝的Objective-C對象, 有啥好處?

  • 中間省略了須要Pthread管理線程生命週期代碼.
  • 更加的面向對象, 簡單易懂, 並且還能夠直接操做線程對象.

以前咱們常常看到[NSThread currentThread]這句代碼, 就是獲取當前線程信息的.


NSThread的使用

如今咱們來看看NSThread的簡單使用:

- (void)nsthread {

    NSThread *thread = [[NSThread alloc] initWithTarget:self
                                               selector:@selector(runTheThread)
                                                 object:nil];

    [thread start];
}

- (void)runTheThread {

    NSLog(@"執行任務, 當前的線程爲: %@", [NSThread currentThread]);
}複製代碼
2017-08-06 20:53:32.129 NSThread-Example[4108:332154] 執行任務, 當前的線程爲: <NSThread: 0x600000265900>{number = 3, name = (null)}複製代碼

除此以外, 咱們還能夠在建立隱式線程並啓動它:

- (void)backgroundThread {

    [self performSelectorOnMainThread:@selector(runTheBackgroundThread)
                           withObject:nil
                        waitUntilDone:YES];
}

- (void)runTheBackgroundThread {

    NSLog(@"執行任務, 當前的線程爲: %@", [NSThread currentThread]);
}複製代碼
2017-08-06 20:57:35.971 NSThread-Example[4159:338649] 執行任務, 當前的線程爲: <NSThread: 0x608000067300>{number = 1, name = main}複製代碼

NSThread的其餘方法

獲取主線程

+ (NSThread *)mainThread;複製代碼

上面有獲取主線程咯, 那這裏也有一個判斷是不是主線程的方法了, 區別在於, 一個是實例方法, 一個是類方法:

@property (readonly) BOOL isMainThread NS_AVAILABLE(10_5, 2_0);

@property (class, readonly) BOOL isMainThread NS_AVAILABLE(10_5, 2_0); // reports whether current thread is main複製代碼

還有咱們以前常常看到的獲取線程方法:

@property (class, readonly, strong) NSThread *currentThread;

[NSThread currentThread];複製代碼

若是你想和GCD那樣設置線程的名字或者是獲取線程的名字, 那麼你能夠用這個:

@property (nullable, copy) NSString *name NS_AVAILABLE(10_5, 2_0);複製代碼

控制線程的狀態

在上面的代碼裏, 咱們能夠看到和NSOperation同樣, 有一個- (void)start方法, 用途是同樣的, 就是啓動線程:

- (void)start NS_AVAILABLE(10_5, 2_0);複製代碼

除了這個以外還有暫停當前線程的方法:

+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;複製代碼

最後還有一個終止當前線程的方法和取消當前線程的方法:

+ (void)exit;

- (void)cancel NS_AVAILABLE(10_5, 2_0);複製代碼

既然這裏提到了操控線程的狀態, 那就得講講, 線程狀態的切換.

當咱們用NSThread建立一條信線程的時候, 內存中會佔用一塊內存, 以下圖:

1
1

一旦咱們經過調用- (void)start以後, 就會把當前的線程對象, 加入到線程池中, 以下圖:

2
2

若是還有其餘線程對象添加進來或者是其餘線程, 就會以下圖所示:

3
3

這裏舉幾個線程切換狀態時的幾個例子:

  • CPU去調用當前線程對象的時候, 那麼當前線程就會進入一個運行狀態, 不然就是準備就緒狀態(好比CPU去調用其餘線程對象), 以下圖:

4
4

  • 若是CPU在運行當前線程對象的時候調用sleep方法或者是同步鎖, 那麼當前線程就會進入一個線程阻塞狀態, 等到sleep方法到時間以後, 或者獲得同步鎖, 就會回到就緒狀態.

5
5

  • 若是CPU在運行當前線程對象的時候, 任務執行完成或者是強制退出, 那麼當前線程對象就會進入一個終止狀態.

6
6


總結

雖然經過蘋果爸爸封裝的NSThread或者是用C寫的Pthread能夠更加直接的操做線程, 但咱們通常不會直接用到NSThreadPthread去操做線程.

直接操做線程的話能夠一不當心就GG了, 什麼意思呢?

好比咱們在一個大項目裏直接操做了線程, 給你個8核CPU, 咱們爲了徹底使用CPU的性能, 可能會建立8條, 或者是16條線程, 然而在咱們代碼調用的框架裏, 又作了相似的操做(代碼不會知道咱們建立了線程), 那麼這時候就會形成上百條, 上千條線程了.

其實代碼自己是沒有問題的, 但因爲咱們的操做不當, 最終就出現了問題, 使用線程都會有消耗一些內存和內核資源, 因此爲了安全起見, 仍是不要直接操做線程了.


工程地址

項目地址: github.com/CainRun/iOS…


最後

碼字很費腦, 看官賞點飯錢可好

微信
微信

支付寶
支付寶
相關文章
相關標籤/搜索