GCD還提供單次初始化支持,這個與pthread中的函數 pthread_once 很相似。GCD提供的方式的優點在於它使用block而非函數指針,這就允許更自然的代碼方式。
這個特性的主要用途是惰性單例初始化或者其他的線程安全數據共享。典型的單例初始化技術看起來像這樣(線程安全的):
01
02
03
04
05
06
07
08
09
10
|
+
(id)sharedWhatever { static Whatever
*whatever = nil; @synchronized([Whatever class ]) { if (!whatever) whatever
= [[Whatever alloc] init]; } return whatever; } |
這挺好的,但是代價比較昂貴;每次調用 +sharedWhatever 函數都會付出取鎖的代價,即使這個鎖只需要進行一次。確實有更風騷的方式來實現這個,使用類似雙向鎖或者是原子操作的東西,但是這樣挺難弄而且容易出錯。創建單例有更加簡單的方式,使用GCD,我們可以這樣重寫上面的方法,使用函數 dispatch_once:
1
2
3
4
5
6
7
8
9
|
+
(id)sharedWhatever { static dispatch_once_t
pred; static Whatever
*whatever = nil; dispatch_once(&pred,
^{ whatever
= [[Whatever alloc] init]; }); return whatever; } |
該方法有很多優勢:
1 線程安全
2 很好滿足靜態分析器要求
3 和自動引用計數(ARC)兼容
4 僅需要少量代碼
這個稍微比 @synchronized方法簡單些,並且GCD確保以更快的方式完成這些檢測,它保證block中的代碼在任何線程通過 dispatch_once 調用之前被執行,但它不會強制每次調用這個函數都讓代碼進行同步控制。實際上,如果你去看這個函數所在的頭文件,你會發現目前它的實現其實是一個宏,進行了內聯的初始化測試,這意味着通常情況下,你不用付出函數調用的負載代價,並且會有更少的同步控制負載。