2009-10-27 37 views
2

我有我的主應用程序委託,它包含一個返回對象的方法。此應用程序委託在主線程上運行。Objective-C 2.0中的多線程問題

我也有一個NSOperation在不同的線程上運行。除了希望能夠在我的主線程上調用我的應用程序委託方法,我還需要從我的NSOperation線程調用它來獲取它返回的對象。我的第一個問題是,如果我把這個從我的其他線程...

id newObject = [[[UIApplication sharedApplication] delegate] myMethod]; 

... ...將是法的同一個線程中的NSOperation上處理,還是會在同一個線程(主)作爲應用程序委託在?

我也想確保myMethod中的代碼一次只能被我的操作線程或我的主線程調用一次。我可以在我的應用程序委託中創建一個NSLock實例var,並執行類似操作:

-(id)myMethod { 
    [myLock lock]; 
    myObject = // Get or create my object to return 
    [myLock unlock]; 
    return myObject; 
} 

感謝您的幫助!

邁克

回答

11

除非你明確地寫代碼,以使東西在另一個線程執行,每一個方法調用將被直接線程它被要求執行。方法調用沒有魔法。出於線程化目的,您可以將其視爲具有與C函數調用完全相同的語義/ ABI。

您的鎖定模式將正常工作以確保跨線程的獨佔訪問。另外

兩個不相關的筆記(因爲在它這麼多人的行程):

  • 聲明財產atomic有一點做與線程安全。原子性只能保證你得到一個有效的值,而不是正確的值(這是有區別的)。

  • 自動釋放對象永遠不會安全地在線程之間傳遞。您需要在發送線程上顯式地發送retain,並且在接收線程上平衡最終的release

+0

感謝您有用的答案:-) – 2009-10-27 18:12:28

+1

難道是肯定地說,一個@synchronized(個體經營)鎖定的方法{}塊會做同樣的事情,一個NSLock實例? – 2009-10-29 17:00:14

+0

或多或少;實施細節略有不同,但影響是一樣的。 – bbum 2009-11-06 16:21:38

3

你絕對需要在NSOperation線程中執行這個調用,而不是簡單地提供所需的對象創建自定義操作的一部分?

如果是這樣,我會建議不要使用鎖定,除非性能是至關重要的。如果iPhone支持的話,你可以使用大中央調度來獲取對象到你的線程:

__block id newObject = nil; 
dispatch_sync(dispatch_get_main_queue(), ^{ 
    newObject = [[[[UIApplication sharedApplication] delegate] myMethod] retain]; 
}); 

對於iPhone,我會很想創建一個輔助方法:

- (void)createNewObject:(NSValue *)returnPtr { 
    id newObject = [[[[UIApplication sharedApplication] delegate] myMethod] retain]; 
    *(id *)[returnPtr pointerValue] = newObject; 
} 

,並調用它從你NSOperation線程像這樣:

id newObject = nil; 
[self performSelectorOnMainThread:@selector(createNewObject:) 
         withObject:[NSValue valueWithPointer:&newObject] 
        waitUntilDone:YES]; 

在主線程實際執行的執行具有較少的隱性風險。

+0

這是一個有趣的方法。我注意到performSelectorOnMainThread方法不允許你返回一個值,但我從來沒有想過傳遞一個指針的地址!出於興趣,演員*(id *)做了什麼?我見過一個類似(NSNumber *)的類型,但我認爲id類型不需要指針asterix。什麼是第一個asterix? – 2009-10-27 18:14:56

+0

如果你真的想在iPhone上執行blocks/GCD,請查看PLBlocks和WiganWallgate項目。 – nall 2009-10-27 18:47:45

+0

cast'(id *)'確保'-pointerValue'方法返回的'void *'被視爲一個指向'id'的指針。第一個'*'將它解引用,以便改變指針的目標而不是指針本身。 – 2009-10-28 02:32:25

2

如果你只需要保護一段關鍵代碼,爲什麼不使用Objective-C @synchronized指令?當然,使用NSLock也可以,但是你需要明確地管理NSLock實例。從文檔:

Objective-C在應用程序中支持多線程。這意味着兩個線程可以嘗試同時修改同一個對象,這種情況可能會在程序中導致嚴重問題。爲了保護代碼段不被一次執行多個線程執行,Objective-C提供了@synchronized()指令。

@synchronized()指令鎖定一段代碼以供單個線程使用。其他線程被阻塞,直到線程退出受保護的代碼;也就是說,當執行繼續超過@synchronized()塊中的最後一條語句時。

@synchronized()指令將任何Objective-C對象(包括self)作爲其唯一參數。這個對象被稱爲互斥信號量或互斥量。它允許線程鎖定一段代碼以防止其他線程使用它。您應該使用單獨的信號來保護程序的不同關鍵部分。在應用程序變爲多線程之前創建所有互斥對象以避免競爭條件是最安全的。

清單12-1顯示了一個代碼示例,它使用self作爲互斥體來同步對當前對象的實例方法的訪問。您可以採用類似的方法來使用Class對象而不是self來同步相關類的類方法。在後一種情況下,一次只允許一個線程執行一個類方法,因爲只有一個類對象被所有的調用者共享。

清單12-1使用自

- (void)criticalMethod 
{ 
    @synchronized(self) { 
     // Critical code. 
     ... 
    } 
} 
+0

看起來很有希望。我唯一不明白的是你傳遞給它的semaphone對象。我沒有得到它的用途!? – 2009-10-28 09:38:05