你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS編程技術 >> iOS 並行編程:Thread

iOS 並行編程:Thread

編輯:IOS編程技術

1 創建線程

1.1 NSThread

      使用 NSThread 來創建線程有兩個可以使用的方法:

      1) 使用 detachNewThreadSelector:toTarget:withObject:類方法來生成一個新的線程

      2) 創建一個新的 NSThread 對象,並調用它的 start 方法。

這兩種創建線程的技術都在你的應用程序裡面新建了一個脫離的線程。 一個脫離的線程意味著當線程退出的時候線程的資源由系統自動回收。

 1 -(void) myThreadMainMethod
 2 {
 3     printf("myThreadMainMethod\n");
 4 }
 5 
 6 -(void) testMethod
 7 {
 8     NSThread* myThread = [[NSThread alloc] initWithTarget: self
 9                                                  selector:@selector(myThreadMainMethod)
10                                                    object:nil];
11     [myThread start];
12 }

      如果你擁有一個 NSThread 對象,它的線程當前真正運行,你可以給該線程發送消息的唯一方法是在你應用程序裡面的任何對象使用performSelector:onThread:withObject:waitUntilDone:方法。

 

1.2 POSIX

      Mac OS X 和 iOS 提供基於 C 語言支持的使用 POSIX 線程 API 來創建線程的方法。

 1 void* PosixThreadMainRoutine(void* data) //這是C語言的普通函數
 2 {
 3     printf("PosixThreadMainRoutine\n");
 4     return NULL;
 5 }
 6 -(void) createPOSIXThreads //這是Object-C類的成員方法
 7 {
 8     pthread_t posixThreadID;
 9     int threadError = pthread_create(&posixThreadID, NULL, &PosixThreadMainRoutine, NULL);
10 }

 

1.3 NSObject

      在 iOS 和 Mac OS X v10.5 及其之後,所有的對象都可能生成一個新的線程,並用它來執行它任意的方法。方法 performSelectorInBackground:withObject:新生成一個脫離的線程,使用指定的方法作為新線程的主體入口點。

比如,你可以使用當前對象創建一個新的線程:

1 -(void) myThreadMainMethod
2 {
3     printf("myThreadMainMethod\n");
4 }

6 -(void) createNSObjectThreads
7 {
8     [self performSelectorInBackground:@selector(myThreadMainMethod) withObject:nil];
9 }

      調用該方法的效果和你在當前對象裡面使用NSThread 的detachNewThreadSelector:toTarget:withObject:傳遞 selectore,object 作為參數的方法一樣。新的線程將會被立即生成並運行,它使用默認的設置。

 

2 run loop

       Run loop 是線程相關的的基礎框架的一部分。一個 run loop 就是一個事件處理的循環,用來不停的調度工作以及處理輸入事件。使用 run loop 的目的是讓你的線程在有工作的時候忙於工作, 而沒工作的時候處於休眠狀態。Run loop相當是Linux系統中的信號處理程序,需要綁定感興趣的信號。

      Run loop 的管理並不完全自動的。你仍然需要設計你的線程代碼在合適的時候啟動 run loop 並正確響應輸入事件。 Cocoa 和 Core Fundation 都自動在你應用程序的主線程啟動一個 run loop objects 來幫助配置和管理你線程的 run loop。你的應用程序不需要顯式的創建這些對象(run loop objects);每個線程,包括程序的主線程都有與之對應的 run loop object。 只有輔助線程才需要顯式的運行它的 run loop。

2.1 剖析

      Run loop是用來響應產生的事件,在代碼中自己實現循環控制語句,來響應接收到的事件並調用處理程序。Run loop 接收輸入事件來自兩種不同的來源:

  • 輸入源(input source):從其它線程或應用傳遞來的異步事件。
  • 定時源 (timer source):是一種同步事件,發生在特定時間或者重復的時間間隔。

      如圖 1所示是run loop與source之間的結構,run loop在接收到input source事件後,就會導致runUntilDate方法退出;而接收到timer source事件後,則不會退出。其中run loop除了能接收source事件外,還能產生notifications(消息),並可以指定observers來接收這些消息。

圖 1

 

2.1.1 模式

      run loop 有如下的幾種模式,每種模式都是用來監聽input source、timer source和notifications事件。每次在運行run loop時都需要為run loop指定某種模式:

 

2.1.2 第一個程序:定時源

如下是一個簡單的定時器功能,其中在0.1秒後將觸發響應方法doFireTimer 。

 1 -(void) doFireTimer //定時器觸發方法
 2 {
 3     printf("doFireTimer\n");
 4 }
 5 
 6 -(void) myThreadMainMethod //線程的入口函數
 7 {
 8     printf("myThreadMainMethod\n");
 9 
10     NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop]; //創建一個run loop對象
11     NSDate* futureDate = [NSDate dateWithTimeIntervalSinceNow:0.1];//設置run loop持續運行的時間
12     NSTimer* myTimer = [[NSTimer alloc] initWithFireDate:futureDate //創建一個定時器對象
13                                                 interval:0.1
14                                                   target:self
15                                                 selector:@selector(doFireTimer)
16                                                 userInfo:nil                                                  repeats:YES]; 
17     [myRunLoop addTimer:myTimer forMode:NSDefaultRunLoopMode]; //將定時器對象添加到run loop對象中。
18     [myRunLoop runUntilDate:futureDate];  //啟動run loop對象。
19 }

 

2.2 使用

2.2.1 獲得

      為了獲得當前線程的 run loop,你可以采用以下任一方式:

      1) 使用 NSRunLoop 的 currentRunLoop 類方法來返回一個NSRunLoop 對象;

      2) 使用CFRunLoopGetCurrent函數返回一個CFRunLoopRef對象。

如:

1 NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop];   //方式1
2 CFRunLoopRef runLoop = CFRunLoopGetCurrent();         //方式2

 

      CFRunLoopRef 是在 CoreFoundation 框架內的,它提供了純 C 函數的 API,所有這些 API 都是線程安全的。NSRunLoop 是基於 CFRunLoopRef 的封裝,提供了面向對象的 API,但是這些 API 不是線程安全的。NSRunLoop 類定義了一個 getCFRunLoop 方法,該方法返回 一個可以傳遞給 Core Foundation 例程的 CFRunLoopRef 類型。因為兩者都指向同一個run loop。

2.2.2 啟動

      run loop有三種啟動方式,不同的啟動方式調用不同的方法,包括以下這些:

表 3

方式

成員函數

描述

無條件

(void)run

最簡單的方法,但也最不推薦使用的,可以添加或刪除輸入源和定時器,但是退出 run loop 的唯一方法是殺死它。沒有任何辦法可以讓這 run loop 運行在自定義模式下。

有限時間

(void)runUntilDate:(NSDate *)limitDate

這種方式一直運行直到到某一事件到達或者規定的時間已經到期。如果是事件到達消息會被傳遞給相應的處理程序來處理,然後run loop 退出。你可以重新啟動 run loop 來等待下一事件。如果是規定時間到期了,你只需簡單的重啟 run loop 或使用此段時間來做任何的其他工作。

特定模式

(BOOL)runMode:(NSString *)mode beforeDate:(NSDate *)limitDate

這種方式是前兩種方式的結合體。

 

2.2.3 退出

      有兩種方法可以讓 run loop 處理事件之前退出:

      1) 給 run loop 設置超時時間

      2) 通知 run loop 停止

2.2.4 時機

      僅當在為你的程序創建輔助線程的時候,你才需要顯式運行一個 run loop。如果你使用 xcode提供的模板創建的程序,那麼永遠不需要自己顯式的調用這些例程。Run loop 在要和線程有更多的交互時才需要,比如以下情況:

  • 使用端口或自定義輸入源來和其他線程通信
  • 使用線程的定時器
  • Cocoa中使用任何performSelector...的方法
  • 使線程周期性工作

2.3 配置

      在你在輔助線程運行 run loop 之前,你必須至少添加一輸入源或定時器給它。 如果 run loop 沒有任何源需要監視的話,它會在你啟動之際立馬退出。

2.3.1 定時源

      為了給Run Loop配置一個定時源,只需創建一個定時器(NSTimer)對象並把它添加到NSRunLoop對象中。 其中定時源也有指針類型:CFRunLoopTimerRef,該類型是配合run loop的指針類型CFRunLoopRef使用的。並且將NSTimer 對象添加到NSRunLoop對象中有兩種方式:自動和手動:

1) 自動

    這種方式是通過調用NSTimer 的靜態方法scheduledTimerWithTimeInterval,從而自動將創建的NSTimer 對象添加到run loop中。

2) 手動

    這種方式是手動創建NSTimer 對象,然後調用NSRunLoop對象的addTimer方法將其添加進入run loop中。

如:

 1 NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop];
 2 NSDate* futureDate = [NSDate dateWithTimeIntervalSinceNow:1.0];
 3 
 4 //自動方式,自動將NSTimer 對象添加到myRunLoop 中。
 5 [NSTimer scheduledTimerWithTimeInterval:0.2
 6             target:self
 7             selector:@selector(myDoFireTimer1:) //這裡的myDoFireTimer1方法是當時間到了後,響應的成員方法。
 8             userInfo:nil
 9             repeats:YES];
10 
11 //手動方式,需要手動調用addTimer方法將myTimer添加到myRunLoop 中
12 NSTimer* myTimer = [[NSTimer alloc] initWithFireDate:futureDate
13                           interval:0.1
14                           target:self
15                           selector:@selector(myDoFireTimer2:)
16                           userInfo:nil
17                           repeats:YES];
18 [myRunLoop addTimer:myTimer forMode:NSDefaultRunLoopMode];

 

2.3.2 觀察者

      除了安裝源,你也可以添加 run loop 觀察者來監視 run loop 的不同執行階段情況。為了給 run loop 添加一個觀察者,你可以創建 CFRunLoopObserverRef 不透明類型,並使用 CFRunLoopAddObserver 將它添加到你的 run loop。Run loop 觀察者必須由 Core foundation 函數創建,即使是 Cocoa 程序。

 1 -(void) myThreadMainMethod
 2 {
 3     printf("myThreadMainMethod\n");
 4     
 5     NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop];
 6     CFRunLoopObserverContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
 7     CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault,kCFRunLoopAllActivities, YES, 0, &myRunLoopObserver, &context);
 8          if (observer)     {         CFRunLoopRef    cfLoop = [myRunLoop getCFRunLoop];         CFRunLoopAddObserver(cfLoop, observer, kCFRunLoopDefaultMode);     }
 9     
10     NSDate* futureDate = [NSDate dateWithTimeIntervalSinceNow:0.1];
11     NSTimer* myTimer = [[NSTimer alloc] initWithFireDate:futureDate
12                                                 interval:0.1
13                                                   target:self
14                                                 selector:@selector(doFireTimer)
15                                                 userInfo:nil                                                  repeats:YES];     [myRunLoop addTimer:myTimer forMode:NSDefaultRunLoopMode];
16     [myRunLoop runUntilDate:futureDate];    
17 }

 

2.3.2 輸入源

      對於Apple提供的guide中有關自定義輸入源和port輸入源真心看不懂,為了內容的完整性,所以將此部分添加在此,若有誰清楚這塊內容的,希望能介紹介紹。

3 參考文獻

      [1] Threading Programming Guide.

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved