iOS中常見(jiàn)多線程方案

NSThread 、 GCD 和 NSOperation 底層都是依賴(lài)于 pthread
GCD
GCD的常用函數(shù)
- GCD中有兩個(gè)用來(lái)執(zhí)行任務(wù)的函數(shù)
- 用同步方式執(zhí)行任務(wù)(在當(dāng)前線程執(zhí)行任務(wù))
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
// queue:隊(duì)列
// block:任務(wù)
- 用異步的方式執(zhí)行任務(wù)
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
GCD的隊(duì)列
- GCD的隊(duì)列可以分為兩大類(lèi)型
- 并發(fā)隊(duì)列(Concurrent Dispatch Queue)
- 可以讓多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行(自動(dòng)開(kāi)啟多個(gè)線程同時(shí)執(zhí)行任務(wù))
- 并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效
- 串行隊(duì)列
- 讓任務(wù)一個(gè)接著一個(gè)地執(zhí)行(一個(gè)任務(wù)執(zhí)行完畢后,再執(zhí)行下一個(gè)任務(wù))
容易混淆的術(shù)語(yǔ)
- 有4個(gè)術(shù)語(yǔ)比較容易混淆:同步、異步、并發(fā)、串行
- 同步和異步主要影響:能不能開(kāi)啟新的線程
- 同步:在當(dāng)前線程中執(zhí)行任務(wù),不具備開(kāi)啟新線程的能力
- 異步:在新的線程中執(zhí)行任務(wù),具備開(kāi)啟新線程的能力
- 并發(fā)和串行主要影響:任務(wù)的執(zhí)行方式
- 并發(fā):多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行
- 串行:一個(gè)任務(wù)執(zhí)行完畢后,再執(zhí)行下一個(gè)任務(wù)
- dispatch_async和dispatch_sync用來(lái)控制是否要開(kāi)啟新的線程,其只是具備開(kāi)啟新線程的能力。
- 主隊(duì)列也是一種特殊的串行隊(duì)列
各種隊(duì)列的執(zhí)行效果
| 并發(fā)隊(duì)列 | 串行隊(duì)列 | 主隊(duì)列 | |
|---|---|---|---|
| 同步 | 沒(méi)有開(kāi)啟新線程 串行執(zhí)行任務(wù) | 同左 | 同左 |
| 異步 | 有開(kāi)啟新線程 并發(fā)執(zhí)行任務(wù) | 有開(kāi)啟新線程 串行執(zhí)行 | 同上 |
- 總結(jié):只要是同步函數(shù)或者是主隊(duì)列就不會(huì)開(kāi)啟新線程,且為串行執(zhí)行任務(wù)
異步:
- 不用等待當(dāng)前語(yǔ)句執(zhí)行完畢,就可以執(zhí)行下一條語(yǔ)句
- 會(huì)開(kāi)啟新線程,異步是多線程的代名詞
同步:
- 必須等待當(dāng)前語(yǔ)句執(zhí)行完畢,才會(huì)執(zhí)行下一條語(yǔ)句
- 不會(huì)開(kāi)啟線程,在當(dāng)前線程執(zhí)行任務(wù)

隊(duì)列組
GCD的帶有 Create 的是不需要釋放的,帶有 CF 的是需要釋放的。
//創(chuàng)建隊(duì)列組
dispatch_group_t group = dispatch_group_create();
//創(chuàng)建并發(fā)隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
//添加異步任務(wù)
dispatch_group_async(group, queue, ^{
for (int i = 0; i < 10; i++)
{
NSLog(@"任務(wù)1-%@",[NSThread currentThread]);
}
});
dispatch_group_async(group, queue, ^{
for (int i = 0; i < 10; i++)
{
NSLog(@"任務(wù)2-%@",[NSThread currentThread]);
}
});
//等前面的任務(wù)執(zhí)行完后會(huì)自動(dòng)執(zhí)行這個(gè)任務(wù)
dispatch_group_notify(group, queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
for (int i = 0; i < 10; i++)
{
NSLog(@"任務(wù)3-%@",[NSThread currentThread]);
}
});
});
死鎖
- 以下代碼會(huì)出現(xiàn)死鎖
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(@"任務(wù)1");
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
NSLog(@"任務(wù)2");
});
NSLog(@"任務(wù)3");
}
出現(xiàn)死鎖的原因:dispatch_sync為同步執(zhí)行,同步的意思是立馬在當(dāng)前線程執(zhí)行任務(wù),執(zhí)行完畢才能繼續(xù)向下執(zhí)行,因此只有執(zhí)行完任務(wù)2才能執(zhí)行任務(wù)3,但是執(zhí)行任務(wù)2必須等上一個(gè)任務(wù)執(zhí)行完才能執(zhí)行2,也就是viewDidLoad執(zhí)行完才能執(zhí)行任務(wù)2,最終任務(wù)3在等任務(wù)2執(zhí)行完,任務(wù)2又在等viewDidLoad執(zhí)行完,而viewDidLoad需要等任務(wù)3執(zhí)行完,最終導(dǎo)致死鎖。
- 這種情況不會(huì)產(chǎn)生死鎖
- (void)test2
{
NSLog(@"任務(wù)1");
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
NSLog(@"任務(wù)2");
});
NSLog(@"任務(wù)3");
}
執(zhí)行的結(jié)果是先輸出任務(wù)1,再輸出任務(wù)3,最后任務(wù)2,不會(huì)死鎖的原因是dispatch_async不要求立馬在當(dāng)前線程同步執(zhí)行任務(wù),在執(zhí)行任務(wù)2的時(shí)候已經(jīng)出了test2的棧了。
- 這種情況也可以產(chǎn)生死鎖
- (void)test3
{
NSLog(@"任務(wù)1");
dispatch_queue_t queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{ //0
NSLog(@"任務(wù)2");
dispatch_sync(queue, ^{ //1
NSLog(@"任務(wù)3");
});
NSLog(@"任務(wù)4");
});
NSLog(@"任務(wù)5");
}
產(chǎn)生死鎖的原因是:dispatch_sync要求立馬在當(dāng)前線程執(zhí)行block1,但要執(zhí)行block1有個(gè)前提條件是block0要從隊(duì)列中執(zhí)行完block1才能執(zhí)行,block0要執(zhí)行的話(huà)block1要執(zhí)行完它才能執(zhí)行任務(wù)4,因此產(chǎn)生死鎖。
- 總結(jié):使用sync函數(shù)向當(dāng)前串行隊(duì)列中添加任務(wù),會(huì)卡住當(dāng)前的串行隊(duì)列(產(chǎn)生死鎖)
- 以下代碼的輸出結(jié)果
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
NSLog(@"1");
[self performSelector:@selector(testLog) withObject:nil afterDelay:.0];
NSLog(@"3");
// [[NSRunLoop currentRunLoop]addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
// [[NSRunLoop currentRunLoop]runMode:NSDefaultRunLoopMode beforeDate: [NSDate distantFuture]];
});
}
- (void )testLog
{
NSLog(@"2");
}
輸出結(jié)果是:1和3,2是不會(huì)輸出的,因?yàn)橛?code>afterDelay的方法是跟runloop有關(guān)的,之所以會(huì)延遲本質(zhì)是向Runloop里面添加timer,其因?yàn)樵谧泳€程里runloop沒(méi)有啟動(dòng)故不會(huì)輸出,如果想要其正常輸出,需要將子線程的runloop啟動(dòng),即把注釋的代碼打開(kāi)即可。
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
NSLog(@"1");
[self performSelector:@selector(testLog) withObject:nil afterDelay:.0];
NSLog(@"3");
}
- (void )testLog
{
NSLog(@"2");
}
這種情況下輸出結(jié)果是:1,3,2
performSelector里沒(méi)有 'afterDelay' 的只是被轉(zhuǎn)換成了 Objc_msgSend,而有 afterDelay 的是跟 RunLoop 相關(guān)的。
多線程的安全隱患
- 可能會(huì)出現(xiàn)的隱患有:
- 資源共享
- 一塊資源可能會(huì)被多個(gè)線程共享,也就是多個(gè)線程可能會(huì)訪問(wèn)同一塊資源
- 比如多個(gè)線程訪問(wèn)同一個(gè)對(duì)象、同一個(gè)變量、同一個(gè)文件
- 當(dāng)多個(gè)線程訪問(wèn)同一塊資源時(shí),很容易引發(fā)數(shù)據(jù)錯(cuò)亂和數(shù)據(jù)安全問(wèn)題,如買(mǎi)票和存錢(qián)取錢(qián)問(wèn)題
多線程安全隱患的解決方案
- 使用線程同步技術(shù)(同步,就是協(xié)同步調(diào),按預(yù)定的先后次序進(jìn)行)
- 常見(jiàn)的線程同步技術(shù)是:加鎖,目的是保證當(dāng)前只有一條線程訪問(wèn),加鎖后記得要解鎖
線程阻塞
常見(jiàn)的線程阻塞有兩種:
- 一種是
sleep - 另外一種是
while循環(huán),忙等,始終在等待直到鎖打開(kāi)。
iOS中的線程同步方案
- OSSpinLock 自旋鎖
- os_unfair_lock
- pthread_mutex
- dispatch_semaphore 信號(hào)量
- dispatch_queue(DISPATCH_QUEUE_SERIAL)
- NSLock
- NSRecursiveLock
- NSCondition
- NSConditionLock
- synchronized
1. OSSpinLock(已過(guò)期)
- OSSpinLock叫做“自旋鎖”,等待鎖的線程會(huì)處于忙等(busy-wait)狀態(tài),一直占用著CPU資源
- 目前已經(jīng)不再安全,可能會(huì)出現(xiàn)優(yōu)先級(jí)反轉(zhuǎn)問(wèn)題:如兩條線程同時(shí)訪問(wèn)
saleTicket方法,如果優(yōu)先級(jí)低的線程先加了鎖,然后優(yōu)先級(jí)高的線程執(zhí)行到這個(gè)方法時(shí)發(fā)現(xiàn)有鎖,其會(huì)在此處忙等(while (是否有鎖) nil),但其由于優(yōu)先級(jí)高CPU給予了大量時(shí)間從而導(dǎo)致優(yōu)先級(jí)低的線程雖然進(jìn)入了方法內(nèi)部,但因優(yōu)先級(jí)低而導(dǎo)致無(wú)法執(zhí)行下一句代碼,導(dǎo)致這把鎖有可能放不開(kāi),造成類(lèi)似死鎖的現(xiàn)象。 - 如果等待鎖的線程優(yōu)先級(jí)較高,它會(huì)一直占用著CPU資源,優(yōu)先級(jí)低的線程就無(wú)法釋放鎖
- 需要導(dǎo)入頭文件
#import <libkern/OSAtomic.h>
以賣(mài)票為例,完整的代碼是下面這樣子的
@interface ViewController ()
@property (nonatomic, assign) NSInteger ticketCount;
@property (nonatomic, assign) OSSpinLock lock; //C語(yǔ)言類(lèi)型的,故用assign
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
//初始化鎖
OSSpinLock lock = OS_SPINLOCK_INIT;
[self ticketTest];
}
- (void)ticketTest
{
self.ticketCount = 15;
dispatch_queue_t queue = dispatch_get_global_queue(0, DISPATCH_QUEUE_PRIORITY_DEFAULT);
dispatch_async(queue, ^{
for (int i = 0; i < 5; i++)
{
[self saleTicket];
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 5; i++)
{
[self saleTicket];
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 5; i++)
{
[self saleTicket];
}
});
}
- (void)saleTicket
{
//加鎖
OSSpinLockLock(&_lock);
NSInteger count = self.ticketCount;
sleep(.2);
count--;
self.ticketCount = count;
NSLog(@"%@-------ticketCount = %ld",[NSThread currentThread],self.ticketCount);
//解鎖
OSSpinLockUnlock(&_lock);
}
@end
- 注意事項(xiàng):在創(chuàng)建鎖時(shí)不能把創(chuàng)建鎖的操作放在
saleTicket里,這樣的話(huà)會(huì)在這個(gè)方法每次執(zhí)行時(shí)創(chuàng)建一個(gè)鎖,各個(gè)線程之間的鎖不共用,因此不能實(shí)現(xiàn)同步的功能。 - 計(jì)算機(jī)在調(diào)度進(jìn)程和線程時(shí)用的都是:時(shí)間片輪轉(zhuǎn)調(diào)度算法,即給每一條線程分配很短的時(shí)間,看越來(lái)像多條線程一塊執(zhí)行一梓,然后如果哪條線程的優(yōu)先級(jí)高的點(diǎn)就會(huì)多執(zhí)行一點(diǎn)時(shí)間。
- OSSpinLock之前是性能最高的一種鎖,因?yàn)樗翘幱诿Φ?,忙等的好處是不?huì)讓線程睡眠,線程一旦睡著,再想把它喚醒,中間也是要耗性能的,也要花時(shí)間。
2. os_unfair_lock
- os_unfair_lock用于取代不安全的OSSpinLock,從iOS10開(kāi)始才支持
- 從底層調(diào)用看,等待os_unfair_lock鎖的線程會(huì)處于休眠狀態(tài),并非忙等
- 需要導(dǎo)入頭文件
#import <os/lock.h>
完整的代碼如下
@interface ViewController ()
@property (nonatomic, assign) NSInteger ticketCount;
@property (nonatomic, assign) os_unfair_lock lock;
@end
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
//初始化
os_unfair_lock unfairLock = OS_UNFAIR_LOCK_INIT;
self.lock = unfairLock;
}
- (void)saleTicket
{
//嘗試加鎖
//os_unfair_lock_trylock(&_lock);
//加鎖2
os_unfair_lock_lock(&_lock);
NSInteger count = self.ticketCount;
sleep(.2);
count--;
self.ticketCount = count;
NSLog(@"%@-------ticketCount = %ld",[NSThread currentThread],self.ticketCount);
//如果忘記解鎖,專(zhuān)業(yè)術(shù)語(yǔ)叫死鎖
os_unfair_lock_unlock(&_lock);
}
3. pthread_mutex
- 帶P開(kāi)頭的一般都是跨平臺(tái)的
- mutex叫做“互斥鎖”,等待鎖的線程會(huì)處于休眠狀態(tài),而“自旋鎖”剛好與這相反,是不休眠,一直旋轉(zhuǎn),一直在等和執(zhí)行代碼。
完整代碼如下:
#import <pthread.h>
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
//初始化屬性
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
//初始化鎖
pthread_mutex_t mutex;
pthread_mutex_init(&_mutex,&attr);
//銷(xiāo)毀屬性
pthread_mutexattr_destroy(&attr);
//嘗試加鎖
pthread_mutex_trylock(&mutex);
//加鎖
pthread_mutex_lock(&_mutex);
//減票操作
//解鎖
pthread_mutex_unlock(&_mutex);
}
- (void)dealloc
{
//銷(xiāo)毀鎖
pthread_mutex_destroy(&_mutex);
}
4.NSLock
-
NSLock是對(duì)mutex普通鎖的封裝,其實(shí)現(xiàn)了NSLocking協(xié)議
@interface NSLock : NSObject <NSLocking>
- (BOOL)tryLock; //嘗試加鎖,如果不能加,返回NO
- (BOOL)lockBeforeDate:(NSDate *)limit; //在這個(gè)時(shí)間點(diǎn)之前如果沒(méi)有等到這個(gè)鎖則休眠,如果到了這個(gè)時(shí)間點(diǎn)還沒(méi)有等到這個(gè)鎖,則加鎖失敗,返回NO
@end
使用方式
- (void)viewDidLoad {
[super viewDidLoad];
NSLock *lock = [[NSLock alloc]init];
[lock lock];
[my test];
[lock unLock];
}
5. NSRecursiveLock
-
NSRecursiveLock也是對(duì)mutex遞歸鎖的封裝,API跟NSLock基本一致
6. NSCondition
-
NSCondition是對(duì)mutex和cond的封裝
@interface NSCondition : NSObject <NSLocking>
- (void)wait;
- (BOOL)waitUntilDate:(NSDate *)limit;
- (void)signal;
- (void)broadcast;
@end
用法如下:
- (void)run
{
[self.condition lock];
//信號(hào),其他鎖也可以用 signal,用于喚醒等待的線程
[self.condition signal];
//等待,一旦設(shè)置為 wait 則其他線程可以加鎖
[self.condition wait];
[self.condition unLock];
}
7. NSConditionLock
-
NSConditionLock是對(duì)NSCondition的進(jìn)一步封裝,可以設(shè)置具體的條件值
@interface NSConditionLock : NSObject <NSLocking>
@property (readonly) NSInteger condition;
- (void)lockWhenCondition:(NSInteger)condition;
- (BOOL)tryLock;
- (BOOL)tryLockWhenCondition:(NSInteger)condition;
- (void)unlockWithCondition:(NSInteger)condition;
- (BOOL)lockBeforeDate:(NSDate *)limit;
- (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;
@end
8. dispatch_semaphore
-
semaphore叫做信號(hào)量 - 信號(hào)量的初始值,可以用來(lái)控制線程并發(fā)訪問(wèn)的最大數(shù)量
- 信號(hào)量的初始值為1,代表同時(shí)只允許1條線程訪問(wèn)資源,保證線程同步
- (void)viewDidLoad {
[super viewDidLoad];
//信號(hào)量的初始值,可以用來(lái)控制線程并發(fā)訪問(wèn)的最大數(shù)量
int value = 1;
//初始化信號(hào)量
dispatch_semaphore_t phore = dispatch_semaphore_create(value);
//如果信號(hào)量的值<=0,當(dāng)前線程就會(huì)進(jìn)入休眠等待(直到信號(hào)量的值>0)
//如果信號(hào)的值>0,就減1,然后往下執(zhí)行后面的代碼,DISPATCH_TIME_FOREVER表示一直等,直到有信號(hào)量的值大于1為止
dispatch_semaphore_wait(phore, DISPATCH_TIME_FOREVER); // 這句代碼使value - 1
//即最多有初始個(gè)值訪問(wèn)下面的代碼
NSLog(@"%@",[NSThread currentThread]);
//讓信號(hào)量的值加1
dispatch_semaphore_signal(phore);
}
9. @synchronized
-
@synchronized是對(duì)mutex遞歸鎖的封裝
- (void)viewDidLoad {
[super viewDidLoad];
//拿self對(duì)象來(lái)做把鎖
@synchronized (self)
{
NSLog(@"%@",[NSThread currentThread]);
}
}
iOS 線程同步方案性能比較
性能從高到低排序
- os_unfair_lock
- OSSpinLock
- dispatch_semaphore
- pthread_mutex
- dispatch_queue(DISPATCH_QUEUE_SERIAL)
- NSLock
- NSCondition
- pthread_mutex(recursive)
- NSRecursiveLock
- NSConditionLock
- @synchronized
其中遞歸鎖的效率最差,不推薦使用,推薦使用的是:dispatch_queue(DISPATCH_QUEUE_SERIAL) 和 pthread_mutex
自旋鎖與互斥鎖對(duì)比
-
什么情況使用自旋鎖比較劃算?
- 預(yù)計(jì)線程等待鎖的時(shí)間很短
- 加鎖的代碼(臨界區(qū))經(jīng)常被調(diào)用,但競(jìng)爭(zhēng)情況很少發(fā)生
- CPU資源不緊張的情況(自旋鎖耗性能)
-
什么情況使用互斥鎖比較劃算?
- 預(yù)計(jì)線程等待鎖的時(shí)間較長(zhǎng)
- 單核處理器
- 臨界區(qū)有IO操作(IO操作占CPU資源)
- 臨界區(qū)代碼復(fù)雜或者循環(huán)量大
- 臨界區(qū)競(jìng)爭(zhēng)非常激烈
atomic
-
atomic一般在Mac上用,在iOS上基本上不用,給屬性加上atomic屬性,可以保證屬性的setter和getter都是原子性操作,相當(dāng)于在getter和setter內(nèi)部增加了線程同步的鎖,但僅限于setter和getter內(nèi)部 - 可以參考源碼
objc4的objc-accesstors.mm -
atomic很耗性能,因此不常用,如果真的需要加鎖,在外面使用的時(shí)候加鎖。
iOS讀寫(xiě)安全方案
-
IO操作,即文件操作
- 1.從文件中讀取內(nèi)容
- 2.往文件中寫(xiě)入內(nèi)容,和讀取不能同時(shí)進(jìn)行
思考如何實(shí)現(xiàn)以下場(chǎng)景
- 同一時(shí)間,只能有1個(gè)線程進(jìn)行寫(xiě)的操作
- 同一時(shí)間,允許有多個(gè)線程進(jìn)行讀的操作
- 同一時(shí)間,不允許既有寫(xiě)的操作,又有讀的操作
上面的場(chǎng)景就是典型的“多讀單寫(xiě)”,經(jīng)常用于文件等數(shù)據(jù)的讀寫(xiě)操作,iOS中的實(shí)現(xiàn)方案有:
- pthread_rwlock::讀寫(xiě)鎖
- dispatch_barrier_async:異步柵欄調(diào)用
pthread_rwlock用法如下:
//初始化鎖
pthread_rwlock_t lock;
pthread_rwlock_init(&lock,NULL);
//讀-加鎖
pthread_rwlock_rdlock(&lock);
//讀-嘗試加鎖
pthread_rwlock_tryrdlock(&lock);
//寫(xiě)-加鎖
pthread_rwlock_wrlock(&lock);
//寫(xiě)-嘗試加鎖
pthread_rwlock_trywrlock(&lock);
//解鎖
pthread_rwlock_unlock(&lock);
pthread_rwlock_destroy(&lock);
pthread_rwlock例子如下:
#import "SecondViewController.h"
#import <pthread.h>>
@interface SecondViewController ()
@property (nonatomic, assign) pthread_rwlock_t lock;
@end
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
pthread_rwlock_init(&_lock,NULL);
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
for (int i = 0; i < 10; i++)
{
dispatch_async(queue, ^{
[self read];
});
dispatch_async(queue, ^{
[self write];
});
}
}
- (void)read
{
pthread_rwlock_rdlock(&_lock);
NSLog(@"%s",__func__);
pthread_rwlock_unlock(&_lock);
}
- (void)write
{
pthread_rwlock_wrlock(&_lock);
NSLog(@"%s",__func__);
pthread_rwlock_wrlock(&_lock);
}
@end
dispatch_barrier_async用法
- 這個(gè)函數(shù)傳入的并發(fā)隊(duì)列必須是自己通過(guò)
dispatch_queue_create創(chuàng)建的 - 如果傳入的是一個(gè)串行或是一個(gè)全局的并發(fā)隊(duì)列,那這個(gè)函數(shù)便等同于
dispatch_async函數(shù)的效果
#import "ThirdViewController.h"
@interface ThirdViewController ()
@property (nonatomic, strong) dispatch_queue_t queue;
@end
@implementation ThirdViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 10; i++)
{
[self read];
[self read];
[self read];
[self write];
}
}
- (void)read
{
dispatch_async(_queue, ^{
NSLog(@"read");
});
}
- (void)write
{
dispatch_barrier_sync(_queue, ^{
NSLog(@"write");
});
}
@end
GUNStep
- GNUStep是GNU計(jì)劃的項(xiàng)目之一,它將Cocoa的OC庫(kù)重新開(kāi)源實(shí)現(xiàn)了一遍,其里面有runloop、runtime等不開(kāi)源代碼的實(shí)現(xiàn)方式
- 源碼地址:http://www.gnustep.org/resources/downloads.php
- 雖然GNUStep不是蘋(píng)果官方源碼,但還是具有一定的參考價(jià)值