欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
iOS多線(xiàn)程編程指南(二)線(xiàn)程管理

線(xiàn)程管理

Mac OS X和iOS里面的每個(gè)進(jìn)程都是有一個(gè)或多個(gè)線(xiàn)程構成,每個(gè)線(xiàn)程都代表一個(gè)代碼的執行路徑。每個(gè)應用程序啟動(dòng)時(shí)候都是一個(gè)線(xiàn)程,它執行程序的main函數。應用程序可以生成額外的線(xiàn)程,其中每個(gè)線(xiàn)程執行一個(gè)特定功能的代碼。

當應用程序生成一個(gè)新的線(xiàn)程的時(shí)候,該線(xiàn)程變成應用程序進(jìn)程空間內的一個(gè)實(shí)體。每個(gè)線(xiàn)程都擁有它自己的執行堆棧,由內核調度獨立的運行時(shí)間片。一個(gè)線(xiàn)程可以和其他線(xiàn)程或其他進(jìn)程通信,執行I/O操作,甚至執行任何你想要它完成的任務(wù)。因為它們處于相同的進(jìn)程空間,所以一個(gè)獨立應用程序里面的所有線(xiàn)程共享相同的虛擬內存空間,并且具有和進(jìn)程相同的訪(fǎng)問(wèn)權限。

本章提供了Mac OS X和iOS上面可用線(xiàn)程技術(shù)的預覽,并給出了如何在你的應用程序里面使用它們的例子。

注意:獲取關(guān)于Mac OS上面線(xiàn)程架構,或者更多關(guān)于線(xiàn)程的背景資料。請參閱技術(shù)說(shuō)明TN2028 --“線(xiàn)程架構”。

1.1        線(xiàn)程成本

多線(xiàn)程會(huì )占用你應用程序(和系統的)的內存使用和性能方面的資源。每個(gè)線(xiàn)程都需要分配一定的內核內存和應用程序內存空間的內存。管理你的線(xiàn)程和協(xié)調其調度所需的核心數據結構存儲在使用Wired Memory的內核里面。你線(xiàn)程的堆??臻g和每個(gè)線(xiàn)程的數據都被存儲在你應用程序的內存空間里面。這些數據結構里面的大部分都是當你首次創(chuàng )建線(xiàn)程或者進(jìn)程的時(shí)候被創(chuàng )建和初始化的,它們所需的代價(jià)成本很高,因為需要和內核交互。

表2-1量化了在你應用程序創(chuàng )建一個(gè)新的用戶(hù)級線(xiàn)程所需的大致成本。這些成本里面的部分是可配置的,比如為輔助線(xiàn)程分配堆??臻g的大小。創(chuàng )建一個(gè)線(xiàn)程所需的時(shí)間成本是粗略估計的,僅用于當互相比較的時(shí)候。線(xiàn)程創(chuàng )建時(shí)間很大程度依賴(lài)于處理器的負載,計算速度,和可用的系統和程序空間。

Table 2-1  Thread creation costs

Item

Approximate cost

Notes

Kernel data structures

Approximately 1 KB

This memory is used to store the thread data structures and attributes, much of which is allocated as wired memory and therefore cannot be paged to disk.

Stack space

512 KB (secondary threads)

8 MB (Mac OS X main thread)

1 MB (iOS main thread)

The minimum allowed stack size for secondary threads is 16 KB and the stack size must be a multiple of 4 KB. The space for this memory is set aside in your process space at thread creation time, but the actual pages associated with that memory are not created until they are needed.

Creation time

Approximately 90 microseconds

This value reflects the time between the initial call to create the thread and the time at which the thread’s entry point routine began executing. The figures were determined by analyzing the mean and median values generated during thread creation on an Intel-based iMac with a 2 GHz Core Duo processor and 1 GB of RAM running Mac OS X v10.5.

注意:因為底層內核的支持,操作對象(Operation objectis)可能創(chuàng )建線(xiàn)程更快。它們使用內核里面常駐線(xiàn)程池里面的線(xiàn)程來(lái)節省創(chuàng )建的時(shí)間,而不是每次都創(chuàng )建新的線(xiàn)程。關(guān)于更多使用操作對象(Operation objects)的信息,參閱并發(fā)編程指南(Concurrency Programming Guide)。

當編寫(xiě)線(xiàn)程代碼時(shí)另外一個(gè)需要考慮的成本是生產(chǎn)成本。設計一個(gè)線(xiàn)程應用程序有時(shí)會(huì )需要根本性改變你應用程序數據結構的組織方式。要做這些改變可能需要避免使用同步,因為本身設計不好的應用可能會(huì )造成巨大的性能損失。設計這些數據結構和在線(xiàn)程代碼里面調試問(wèn)題會(huì )增加開(kāi)發(fā)一個(gè)線(xiàn)程應用所需的時(shí)間。然而避免這些消耗的話(huà),可能在運行時(shí)候帶來(lái)更大的問(wèn)題,如果你的多線(xiàn)程花費太多的時(shí)間在鎖的等待而沒(méi)有做任何事情。

1.1        創(chuàng )建一個(gè)線(xiàn)程

創(chuàng )建低級別的線(xiàn)程相對簡(jiǎn)單。在所有情況下,你必須有一個(gè)函數或方法作為線(xiàn)程的主入口點(diǎn),你必須使用一個(gè)可用的線(xiàn)程例程啟動(dòng)你的線(xiàn)程。以下幾個(gè)部分介紹了比較常用線(xiàn)程創(chuàng )建的基本線(xiàn)程技術(shù)。線(xiàn)程創(chuàng )建使用了這些技術(shù)的繼承屬性的默認設置,由你所使用的技術(shù)來(lái)決定。關(guān)于更多如何配置你的線(xiàn)程的信息,參閱“線(xiàn)程屬性配置”部分。

1.1.1    使用NSThread

使用NSThread來(lái)創(chuàng )建線(xiàn)程有兩個(gè)可以的方法:

  1. 使用detachNewThreadSelector:toTarget:withObject:類(lèi)方法來(lái)生成一個(gè)新的線(xiàn)程。
  2. 創(chuàng )建一個(gè)新的NSThread對象,并調用它的start方法。(僅在iOS和Mac OS X v10.5及其之后才支持)

這兩種創(chuàng )建線(xiàn)程的技術(shù)都在你的應用程序里面新建了一個(gè)脫離的線(xiàn)程。一個(gè)脫離的線(xiàn)程意味著(zhù)當線(xiàn)程退出的時(shí)候線(xiàn)程的資源由系統自動(dòng)回收。這也同樣意味著(zhù)之后不需要在其他線(xiàn)程里面顯式的連接(join)。因為detachNewThreadSelctor:toTarget:withObject:方法在Mac OS X的任何版本都支持,所以在Cocoa應用里面使用多線(xiàn)程的地方經(jīng)??梢园l(fā)現它。為了生成一個(gè)新的線(xiàn)程,你只要簡(jiǎn)單的提供你想要使用為線(xiàn)程主體入口的方法的名稱(chēng)(被指定為一個(gè)selector),和任何你想在啟動(dòng)時(shí)傳遞給線(xiàn)程的數據。下面的示例演示了這種方法的基本調用,來(lái)使用當前對象的自定義方法來(lái)生成一個(gè)線(xiàn)程。

1
[NSThread detachNewThreadSelector:@selector(myThreadMainMethod:) toTarget:self withObject:nil];

在Mac OS X v10.5之前,你使用NSThread類(lèi)來(lái)生成多線(xiàn)程。雖然你可以獲取一個(gè)NSThread對象并訪(fǎng)問(wèn)線(xiàn)程的屬性,但你只能在線(xiàn)程運行之后在其內部做到這些。在Mac OS X v10.5支持創(chuàng )建一個(gè)NSThread對象,而無(wú)需立即生成一個(gè)相應的新線(xiàn)程(這些在iOS里面同樣可用)。新版支持使得在線(xiàn)程啟動(dòng)之前獲取并設置線(xiàn)程的很多屬性成為可能。這也讓用線(xiàn)程對象來(lái)引用正在運行的線(xiàn)程成為可能。

在Mac OS X v10.5及其之后初始化一個(gè)NSThread對象的簡(jiǎn)單方法是使用initWithTarget:selector:object:方法。該方法和detachNewThreadSelector:toTarget:withObject:方法來(lái)初始化一個(gè)新的NSThread實(shí)例需要相同的額外開(kāi)銷(xiāo)。然而它并沒(méi)有啟動(dòng)一個(gè)線(xiàn)程。為了啟動(dòng)一個(gè)線(xiàn)程,你可以顯式調用先對象的start方法,如下面代碼:

1
2
3
4
NSThread* myThread = [[NSThread alloc] initWithTarget:self
                                        selector:@selector(myThreadMainMethod:)
                                        object:nil];
[myThread start];  // Actually create the thread

注意:使用initWithTarget:selector:object:方法的替代辦法是子類(lèi)化NSThread,并重寫(xiě)它的main方法。你可以使用你重寫(xiě)的該方法的版本來(lái)實(shí)現你線(xiàn)程的主體入口。更多信息,請參閱NSThread Class Reference里面子類(lèi)化的提示。

如果你擁有一個(gè)NSThread對象,它的線(xiàn)程當前真正運行,你可以給該線(xiàn)程發(fā)送消息的唯一方法是在你應用程序里面的任何對象使用performSelector:onThread:withObject:waitUntilDone:方法。在Mac OS X v10.5支持在多線(xiàn)程上面執行selectors(而不是在主線(xiàn)程里面),并且它是實(shí)現線(xiàn)程間通信的便捷方法。你使用該技術(shù)時(shí)所發(fā)送的消息會(huì )被其他線(xiàn)程作為run-loop主體的一部分直接執行(當然這些意味著(zhù)目標線(xiàn)程必須在它的run loop里面運行,參閱“ Run Loops”)。當你使用該方法來(lái)實(shí)現線(xiàn)程通信的時(shí)候,你可能仍然需要一個(gè)同步操作,但是這比在線(xiàn)程間設置通信端口簡(jiǎn)單多了。

注意:雖然在線(xiàn)程間的偶爾通信的時(shí)候使用該方法很好,但是你不能周期的或頻繁的使用performSelector:onThread:withObject:waitUntilDone:來(lái)實(shí)現線(xiàn)程間的通信。

關(guān)于線(xiàn)程間通信的可選方法,參閱“設置線(xiàn)程的脫離狀態(tài)”部分。

1.1.2    使用POSIX的多線(xiàn)程

Mac OS X和iOS提供基于C語(yǔ)言支持的使用POSIX線(xiàn)程API來(lái)創(chuàng )建線(xiàn)程的方法。該技術(shù)實(shí)際上可以被任何類(lèi)型的應用程序使用(包括Cocoa和Cocoa Touch的應用程序),并且如果你當前真為多平臺開(kāi)發(fā)應用的話(huà),該技術(shù)可能更加方便。你使用來(lái)創(chuàng )建線(xiàn)程的POSIX例程被調用的時(shí)候,使用pthread_create剛好足夠。

列表2-1顯示了兩個(gè)使用POSIX來(lái)創(chuàng )建線(xiàn)程的自定義函數。LaunchThread函數創(chuàng )建了一個(gè)新的線(xiàn)程,該線(xiàn)程的例程由PosixThreadMainRoutine函數來(lái)實(shí)現。因為POSIX創(chuàng )建的線(xiàn)程默認情況是可連接的(joinable),下面的例子改變線(xiàn)程的屬性來(lái)創(chuàng )建一個(gè)脫離的線(xiàn)程。把線(xiàn)程標記為脫離的,當它退出的時(shí)候讓系統有機會(huì )立即回收該線(xiàn)程的資源。

Listing 2-1  Creating a thread in C

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include  <assert.h>
#include  <pthread.h>
void* PosixThreadMainRoutine(void* data)
{
    // Do some work here.
    return NULL;
}
void LaunchThread()
{
    // Create the thread using POSIX routines.
    pthread_attr_t  attr;
    pthread_t       posixThreadID;
    int             returnVal;
    returnVal = pthread_attr_init(&attr);
    assert(!returnVal);
    returnVal = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    assert(!returnVal);
    int     threadError = pthread_create(&posixThreadID, &attr, &PosixThreadMainRoutine, NULL);
    returnVal = pthread_attr_destroy(&attr);
    assert(!returnVal);
    if (threadError != 0)
    {
         // Report an error.
    }
}

    如果你把上面列表的代碼添加到你任何一個(gè)源文件,并且調用LaunchThread函數,它將會(huì )在你的應用程序里面創(chuàng )建一個(gè)新的脫離線(xiàn)程。當然,新創(chuàng )建的線(xiàn)程使用該代碼沒(méi)有做任何有用的事情。線(xiàn)程將會(huì )加載并立即退出。為了讓它更有興趣,你需要添加代碼到PosixThreadMainRoutine函數里面來(lái)做一些實(shí)際的工作。為了保證線(xiàn)程知道該干什么,你可以在創(chuàng )建的時(shí)候給線(xiàn)程傳遞一個(gè)數據的指針。把該指針作為pthread_create的最后一個(gè)參數。

為了在新建的線(xiàn)程里面和你應用程序的主線(xiàn)程通信,你需要建立一條和目標線(xiàn)程之間的穩定的通信路徑。對于基于C語(yǔ)言的應用程序,有幾種辦法來(lái)實(shí)現線(xiàn)程間的通信,包括使用端口(ports),條件(conditions)和共享內存(shared memory)。對于長(cháng)期存在的線(xiàn)程,你應該幾乎總是成立某種線(xiàn)程間的通信機制,讓你的應用程序的主線(xiàn)程有辦法來(lái)檢查線(xiàn)程的狀態(tài)或在應用程序退出時(shí)干凈關(guān)閉它。

關(guān)于更多介紹POSIX線(xiàn)程函數的信息,參閱pthread的主頁(yè)。

1.1.3    使用NSObject來(lái)生成一個(gè)線(xiàn)程

在iOS和Mac OS X v10.5及其之后,所有的對象都可能生成一個(gè)新的線(xiàn)程,并用它來(lái)執行它任意的方法。方法performSelectorInBackground:withObject:新生成一個(gè)脫離的線(xiàn)程,使用指定的方法作為新線(xiàn)程的主體入口點(diǎn)。比如,如果你有一些對象(使用變量myObj來(lái)代表),并且這些對象擁有一個(gè)你想在后臺運行的doSomething的方法,你可以使用如下的代碼來(lái)生成一個(gè)新的線(xiàn)程:

1
[myObj performSelectorInBackground:@selector(doSomething) withObject:nil];

調用該方法的效果和你在當前對象里面使用NSThread的detachNewThreadSelector:toTarget:withObject:傳遞selectore,object作為參數的方法一樣。新的線(xiàn)程將會(huì )被立即生成并運行,它使用默認的設置。在selectore內部,你必須配置線(xiàn)程就像你在任何線(xiàn)程里面一樣。比如,你可能需要設置一個(gè)自動(dòng)釋放池(如果你沒(méi)有使用垃圾回收機制),在你要使用它的時(shí)候配置線(xiàn)程的run loop。關(guān)于更是介紹如果配置線(xiàn)程的信息,參閱“配置線(xiàn)程屬性”部分。

1.1.4    使用其他線(xiàn)程技術(shù)

盡管POSIX例程和NSThread類(lèi)被推薦使用來(lái)創(chuàng )建低級線(xiàn)程,但是其他基于C語(yǔ)言的技術(shù)在Mac OS X上面同樣可用。在這其中,唯一一個(gè)可以考慮使用的是多處理服務(wù)(Multiprocessing Services),它本身就是在POSIX線(xiàn)程上執行。多處理服務(wù)是專(zhuān)門(mén)為早期的Mac OS版本開(kāi)發(fā)的,后來(lái)在Mac OS X里面的Carbon應用程序上面同樣適用。如果你有代碼真是有該技術(shù),你可以繼續使用它,盡管你應該把這些代碼轉化為POSIX。該技術(shù)在iOS上面不可用。

關(guān)于更多如何使用多處理服務(wù)的信息,參閱多處理服務(wù)編程指南(Multiprocessing Services Programming Guide)。

1.1.5    在Cocoa程序上面使用POSIX線(xiàn)程

經(jīng)管NSThread類(lèi)是Cocoa應用程序里面創(chuàng )建多線(xiàn)程的主要接口,如果可以更方便的話(huà)你可以任意使用POSIX線(xiàn)程帶替代。例如,如果你的代碼里面已經(jīng)使用了它,而你又不想改寫(xiě)它的話(huà),這時(shí)你可能需要使用POSIX多線(xiàn)程。如果你真打算在Cocoa程序里面使用POSIX線(xiàn)程,你應該了解如果在Cocoa和線(xiàn)程間交互,并遵循以下部分的一些指南。

u  Cocoa框架的保護

對于多線(xiàn)程的應用程序,Cocoa框架使用鎖和其他同步方式來(lái)保證代碼的正確執行。為了保護這些鎖造成在單線(xiàn)程里面性能的損失,Cocoa直到應用程序使用NSThread類(lèi)生成它的第一個(gè)新的線(xiàn)程的時(shí)候才創(chuàng )建這些鎖。如果你僅且使用POSIX例程來(lái)生成新的線(xiàn)程,Cocoa不會(huì )收到關(guān)于你的應用程序當前變?yōu)槎嗑€(xiàn)程的通知。當這些剛好發(fā)生的時(shí)候,涉及Cocoa框架的操作哦可能會(huì )破壞甚至讓你的應用程序崩潰。

為了讓Cocoa知道你正打算使用多線(xiàn)程,你所需要做的是使用NSThread類(lèi)生成一個(gè)線(xiàn)程,并讓它立即退出。你線(xiàn)程的主體入口點(diǎn)不需要做任何事情。只需要使用NSThread來(lái)生成一個(gè)線(xiàn)程就足夠保證Cocoa框架所需的鎖到位。

如果你不確定Cocoa是否已經(jīng)知道你的程序是多線(xiàn)程的,你可以使用NSThread的isMultiThreaded方法來(lái)檢驗一下。

u  混合POSIX和Cocoa的鎖

在同一個(gè)應用程序里面混合使用POSIX和Cocoa的鎖很安全。Cocoa鎖和條件對象基本上只是封裝了POSIX的互斥體和條件。然而給定一個(gè)鎖,你必須總是使用同樣的接口來(lái)創(chuàng )建和操縱該鎖。換言之,你不能使用Cocoa的NSLock對象來(lái)操縱一個(gè)你使用pthread_mutex_init函數生成的互斥體,反之亦然。

1.2        配置線(xiàn)程屬性

創(chuàng )建線(xiàn)程之后,或者有時(shí)候是之前,你可能需要配置不同的線(xiàn)程環(huán)境。以下部分描述了一些你可以做的改變,和在什么時(shí)候你需要做這些改變。

1.2.1    配置線(xiàn)程的堆棧大小

對于每個(gè)你新創(chuàng )建的線(xiàn)程,系統會(huì )在你的進(jìn)程空間里面分配一定的內存作為該線(xiàn)程的堆棧。該堆棧管理堆棧幀,也是任何線(xiàn)程局部變量聲明的地方。給線(xiàn)程分配的內存大小在“線(xiàn)程成本”里面已經(jīng)列舉了。

如果你想要改變一個(gè)給定線(xiàn)程的堆棧大小,你必須在創(chuàng )建該線(xiàn)程之前做一些操作。所有的線(xiàn)程技術(shù)提供了一些辦法來(lái)設置線(xiàn)程堆棧的大小。雖然可以使用NSThread來(lái)設置堆棧大小,但是它只能在iOS和Mac OS X v10.5及其之后才可用。表2-2列出了每種技術(shù)的對于不同的操作。

Table 2-2  Setting the stack size of a thread

Technology

Option

Cocoa

In iOS and Mac OS X v10.5 and later, allocate and initialize an NSThread object (do not use thedetachNewThreadSelector:toTarget:withObject: method). Before calling the start method of the thread object, use thesetStackSize: method to specify the new stack size.

POSIX

Create a new pthread_attr_t structure and use the pthread_attr_setstacksize function to change the default stack size. Pass the attributes to the pthread_create function when creating your thread.

Multiprocessing Services

Pass the appropriate stack size value to the MPCreateTask function when you create your thread.

1.2.2    配置線(xiàn)程本地存儲

每個(gè)線(xiàn)程都維護了一個(gè)鍵-值的字典,它可以在線(xiàn)程里面的任何地方被訪(fǎng)問(wèn)。你可以使用該字典來(lái)保存一些信息,這些信息在整個(gè)線(xiàn)程的執行過(guò)程中都保持不變。比如,你可以使用它來(lái)存儲在你的整個(gè)線(xiàn)程過(guò)程中Run loop里面多次迭代的狀態(tài)信息。

Cocoa和POSIX以不同的方式保存線(xiàn)程的字典,所以你不能混淆并同時(shí)調用者兩種技術(shù)。然而只要你在你的線(xiàn)程代碼里面堅持使用了其中一種技術(shù),最終的結果應該是一樣的。在Cocoa里面,你使用NSThread的threadDictionary方法來(lái)檢索一個(gè)NSMutableDictionary對象,你可以在它里面添加任何線(xiàn)程需要的鍵。在POSIX里面,你使用pthread_setspecific和pthread_getspecific函數來(lái)設置和訪(fǎng)問(wèn)你線(xiàn)程的鍵和值。

1.2.3    設置線(xiàn)程的脫離狀態(tài)

大部分上層的線(xiàn)程技術(shù)都默認創(chuàng )建了脫離線(xiàn)程(Datached thread)。大部分情況下,脫離線(xiàn)程(Detached thread)更受歡迎,因為它們允許系統在線(xiàn)程完成的時(shí)候立即釋放它的數據結構。脫離線(xiàn)程同時(shí)不需要顯示的和你的應用程序交互。意味著(zhù)線(xiàn)程檢索的結果由你來(lái)決定。相比之下,系統不回收可連接線(xiàn)程(Joinable thread)的資源直到另一個(gè)線(xiàn)程明確加入該線(xiàn)程,這個(gè)過(guò)程可能會(huì )阻止線(xiàn)程執行加入。

你可以認為可連接線(xiàn)程類(lèi)似于子線(xiàn)程。雖然你作為獨立線(xiàn)程運行,但是可連接線(xiàn)程在它資源可以被系統回收之前必須被其他線(xiàn)程連接。可連接線(xiàn)程同時(shí)提供了一個(gè)顯示的方式來(lái)把數據從一個(gè)正在退出的線(xiàn)程傳遞到其他線(xiàn)程。在它退出之前,可連接線(xiàn)程可以傳遞一個(gè)數據指針或者其他返回值給pthread_exit函數。其他線(xiàn)程可以通過(guò)pthread_join函數來(lái)拿到這些數據。

重要:在應用程序退出時(shí),脫離線(xiàn)程可以立即被中斷,而可連接線(xiàn)程則不可以。每個(gè)可連接線(xiàn)程必須在進(jìn)程被允許可以退出的時(shí)候被連接。所以當線(xiàn)程處于周期性工作而不允許被中斷的時(shí)候,比如保存數據到硬盤(pán),可連接線(xiàn)程是最佳選擇。

如果你想要創(chuàng )建可連接線(xiàn)程,唯一的辦法是使用POSIX線(xiàn)程。POSIX默認創(chuàng )建的線(xiàn)程是可連接的。為了把線(xiàn)程標記為脫離的或可連接的,使用pthread_attr_setdetachstate函數來(lái)修改正在創(chuàng )建的線(xiàn)程的屬性。在線(xiàn)程啟動(dòng)后,你可以通過(guò)調用pthread_detach函數來(lái)把線(xiàn)程修改為可連接的。關(guān)于更多POSIX線(xiàn)程函數信息,參與pthread主頁(yè)。關(guān)于更多如果連接一個(gè)線(xiàn)程,參閱pthread_join的主頁(yè)。

1.2.4    設置線(xiàn)程的優(yōu)先級

你創(chuàng )建的任何線(xiàn)程默認的優(yōu)先級是和你本身線(xiàn)程相同。內核調度算法在決定該運行那個(gè)線(xiàn)程時(shí),把線(xiàn)程的優(yōu)先級作為考量因素,較高優(yōu)先級的線(xiàn)程會(huì )比較低優(yōu)先級的線(xiàn)程具有更多的運行機會(huì )。較高優(yōu)先級不保證你的線(xiàn)程具體執行的時(shí)間,只是相比較低優(yōu)先級的線(xiàn)程,它更有可能被調度器選擇執行而已。

重要:讓你的線(xiàn)程處于默認優(yōu)先級值是一個(gè)不錯的選擇。增加某些線(xiàn)程的優(yōu)先級,同時(shí)有可能增加了某些較低優(yōu)先級線(xiàn)程的饑餓程度。如果你的應用程序包含較高優(yōu)先級和較低優(yōu)先級線(xiàn)程,而且它們之間必須交互,那么較低優(yōu)先級的饑餓狀態(tài)有可能阻塞其他線(xiàn)程,并造成性能瓶頸。

如果你想改變線(xiàn)程的優(yōu)先級,Cocoa和POSIX都提供了一種方法來(lái)實(shí)現。對于Cocoa線(xiàn)程而言,你可以使用NSThread的setThreadPriority:類(lèi)方法來(lái)設置當前運行線(xiàn)程的優(yōu)先級。對于POSIX線(xiàn)程,你可以使用pthread_setschedparam函數來(lái)實(shí)現。關(guān)于更多信息,參與NSThread Class Reference或pthread_setschedparam主頁(yè)。

1.3        編寫(xiě)你線(xiàn)程的主體入口點(diǎn)

對于大部分而言,Mac OS X上面線(xiàn)程結構的主體入口點(diǎn)和其他平臺基本一樣。你需要初始化你的數據結構,做一些工作或可行的設置一個(gè)run loop,并在線(xiàn)程代碼被執行完后清理它。根據設計,當你寫(xiě)的主體入口點(diǎn)的時(shí)候有可能需要采取一些額外的步驟。

1.3.1    創(chuàng )建一個(gè)自動(dòng)釋放池(Autorelease Pool)

在Objective - C框架鏈接的應用程序,通常在它們的每一個(gè)線(xiàn)程必須創(chuàng )建至少一個(gè)自動(dòng)釋放池。如果應用程序使用管理模型,即應用程序處理的retain和release對象,那么自動(dòng)釋放池捕獲任何從該線(xiàn)程autorelease的對象。

如果應用程序使用的垃圾回收機制,而不是管理的內存模型,那么創(chuàng )建一個(gè)自動(dòng)釋放池不是絕對必要的。在垃圾回收的應用程序里面,一個(gè)自動(dòng)釋放池是無(wú)害的,而且大部分情況是被忽略。允許通過(guò)個(gè)代碼管理必須同時(shí)支持垃圾回收和內存管理模型。在這種情況下,內存管理模型必須支持自動(dòng)釋放池,當應用程序運行垃圾回收的時(shí)候,自動(dòng)釋放池只是被忽略而已。

如果你的應用程序使用內存管理模型,在你編寫(xiě)線(xiàn)程主體入口的時(shí)候第一件事情就是創(chuàng )建一個(gè)自動(dòng)釋放池。同樣,在你的線(xiàn)程最后應該銷(xiāo)毀該自動(dòng)釋放池。該池保證自動(dòng)釋放。雖然對象被調用,但是它們不被release直到線(xiàn)程退出。列表2-2顯示了線(xiàn)程主體入口使用自動(dòng)釋放池的基本結構。

Listing 2-2  Defining your thread entry point routine

1
2
3
4
5
6
- (void)myThreadMainRoutine
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // Top-level pool
    // Do thread work here.
    [pool release];  // Release the objects in the pool.
}

    因為高級的自動(dòng)釋放池不會(huì )釋放它的對象直到線(xiàn)程退出。長(cháng)時(shí)運行的線(xiàn)程需求新建額外的自動(dòng)釋放池來(lái)更頻繁的釋放它的對象。比如,一個(gè)使用run loop的線(xiàn)程可能在每次運行完一次循環(huán)的時(shí)候創(chuàng )建并釋放該自動(dòng)釋放池。更頻繁的釋放對象可以防止你的應用程序內存占用太大造成性能問(wèn)題。雖然對于任何與性能相關(guān)的行為,你應該測量你代碼的實(shí)際表現,并適當地調整使用自動(dòng)釋放池。

關(guān)于更多內存管理的信息和自動(dòng)釋放池,參閱“內存高級管理編程指南(Advanced Memory Management Programming Guide)”。

1.3.2    設置異常處理

如果你的應用程序捕獲并處理異常,那么你的線(xiàn)程代碼應該時(shí)刻準備捕獲任何可能發(fā)生的異常。雖然最好的辦法是在異常發(fā)生的地方捕獲并處理它,但是如果在你的線(xiàn)程里面捕獲一個(gè)拋出的異常失敗的話(huà)有可能造成你的應用程序強退。在你線(xiàn)程的主體入口點(diǎn)安裝一個(gè)try/catch模塊,可以讓你捕獲任何未知的異常,并提供一個(gè)合適的響應。

當在Xcode構建你項目的時(shí)候,你可以使用C 或者Objective-C的異常處理風(fēng)格。 關(guān)于更多設置如何在Objective-C里面拋出和捕獲異常的信息,參閱Exception Programming Topics。

1.3.3    設置一個(gè)Run Loop

當你想編寫(xiě)一個(gè)獨立運行的線(xiàn)程時(shí),你有兩種選擇。第一種選擇是寫(xiě)代碼作為一個(gè)長(cháng)期的任務(wù),很少甚至不中斷,線(xiàn)程完成的時(shí)候退出。第二種選擇是把你的線(xiàn)程放入一個(gè)循環(huán)里面,讓它動(dòng)態(tài)的處理到來(lái)的任務(wù)請求。第一種方法不需要在你的代碼指定任何東西;你只需要啟動(dòng)的時(shí)候做你打算做的事情即可。然而第二種選擇需要在你的線(xiàn)程里面添加一個(gè)run loop。

Mac OS X和iOS提供了在每個(gè)線(xiàn)程實(shí)現run loop內置支持。Cocoa、Carbon和UIKit自動(dòng)在你應用程序的主線(xiàn)程啟動(dòng)一個(gè)run loop,但是如果你創(chuàng )建任何輔助線(xiàn)程,你必須手工的設置一個(gè)run loop并啟動(dòng)它。

關(guān)于更多使用和配置run loop的信息,參閱“Run Loops”部分。

1.4        中斷線(xiàn)程

退出一個(gè)線(xiàn)程推薦的方法是讓它在它主體入口點(diǎn)正常退出。經(jīng)管Cocoa、POSIX和Multiprocessing Services提供了直接殺死線(xiàn)程的例程,但是使用這些例程是強烈不鼓勵的。殺死一個(gè)線(xiàn)程阻止了線(xiàn)程本身的清理工作。線(xiàn)程分配的內存可能造成泄露,并且其他線(xiàn)程當前使用的資源可能沒(méi)有被正確清理干凈,之后造成潛在的問(wèn)題。

如果你的應用程序需要在一個(gè)操作中間中斷一個(gè)線(xiàn)程,你應該設計你的線(xiàn)程響應取消或退出的消息。對于長(cháng)時(shí)運行的操作,這意味著(zhù)周期性停止工作來(lái)檢查該消息是否到來(lái)。如果該消息的確到來(lái)并要求線(xiàn)程退出,那么線(xiàn)程就有機會(huì )來(lái)執行任何清理和退出工作;否則,它返回繼續工作和處理下一個(gè)數據塊。

響應取消消息的一個(gè)方法是使用run loop的輸入源來(lái)接收這些消息。列表2-3顯示了該結構的類(lèi)似代碼在你的線(xiàn)程的主體入口里面是怎么樣的(該示例顯示了主循環(huán)部分,不包括設立一個(gè)自動(dòng)釋放池或配置實(shí)際的工作步驟)。該示例在run loop上面安裝了一個(gè)自定義的輸入源,它可以從其他線(xiàn)程接收消息。關(guān)于更多設置輸入源的信息,參閱“配置Run Loop源”。執行工作的總和的一部分后,線(xiàn)程運行的run loop來(lái)查看是否有消息抵達輸入源。如果沒(méi)有,run loop立即退出,并且循環(huán)繼續處理下一個(gè)數據塊。因為該處理器并沒(méi)有直接的訪(fǎng)問(wèn)exitNow局部變量,退出條件是通過(guò)線(xiàn)程的字典來(lái)傳輸的。

Listing 2-3  Checking for an exit condition during a long job

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- (void)threadMainRoutine
{
    BOOL moreWorkToDo = YES;
    BOOL exitNow = NO;
    NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
    // Add the exitNow BOOL to the thread dictionary.
    NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary];
    [threadDict setValue:[NSNumber numberWithBool:exitNow] forKey:@'ThreadShouldExitNow'];
    // Install an input source.
    [self myInstallCustomInputSource];
    while (moreWorkToDo && !exitNow)
    {
        // Do one chunk of a larger body of work here.
        // Change the value of the moreWorkToDo Boolean when done.
        // Run the run loop but timeout immediately if the input source isn't waiting to fire.
        [runLoop runUntilDate:[NSDate date]];
        // Check to see if an input source handler changed the exitNow value.
        exitNow = [[threadDict valueForKey:@'ThreadShouldExitNow'] boolValue];
    }
}
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
QNX system architecture 2
SimpleLink MCU SDK用戶(hù)指南
Windows多線(xiàn)程多任務(wù)設計初步
線(xiàn)程文化
【MFC】AfxGetMainWnd()函數使用心得
線(xiàn)程的基本概念和調度策略
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久