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

GCD
GCD中有2個(gè)用來(lái)執(zhí)行任務(wù)的函數(shù)
- 用同步的方式執(zhí)行任務(wù)
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block); - 用異步的方式執(zhí)行任務(wù)
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
GCD源碼:https://github.com/apple/swift-corelibs-libdispatch
GCD的隊(duì)列
GCD的隊(duì)列可以分為2大類(lèi)型
- 并發(fā)隊(duì)列(Concurrent Dispatch Queue)
可以讓多個(gè)任務(wù)并發(fā)執(zhí)行(自動(dòng)開(kāi)啟多個(gè)線程同時(shí)執(zhí)行任務(wù))
并發(fā)功能只有在異步函數(shù)下才有效 - 串行隊(duì)列(Serial Dispatch Queue)
讓任務(wù)一個(gè)接著一個(gè)地執(zhí)行
同步和異步主要影響:能不能開(kāi)啟新的線程
同步:在當(dāng)前線程中執(zhí)行任務(wù),不具備開(kāi)啟新線程的能力
異步:在新的線程中執(zhí)行任務(wù),具備開(kāi)啟新線程的能力
并發(fā)和串行主要影響:任務(wù)的執(zhí)行方式
并發(fā):多個(gè)任務(wù)并發(fā)執(zhí)行
串行:一個(gè)任務(wù)執(zhí)行完畢后,再執(zhí)行下一個(gè)任務(wù)
使用
sync函數(shù)往當(dāng)前串行隊(duì)列中添加任務(wù),會(huì)卡住當(dāng)前的串行隊(duì)列(產(chǎn)生死鎖)
GCD Group
下面場(chǎng)景如何實(shí)現(xiàn)?
- 異步并發(fā)執(zhí)行任務(wù)1、任務(wù)2
- 等任務(wù)1、任務(wù)2都執(zhí)行完畢后,再回到主線程執(zhí)行任務(wù)3
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_async(group, queue, ^{
NSLog(@"Task-1");
});
dispatch_group_async(group, queue, ^{
NSLog(@"Task-2");
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"Task-3");
});
iOS中的線程同步方案
當(dāng)多個(gè)線程訪問(wèn)同一塊資源時(shí),很容易引發(fā)數(shù)據(jù)錯(cuò)亂和數(shù)據(jù)安全問(wèn)題。
常見(jiàn)的解決方案:使用線程同步技術(shù)。
iOS中,常見(jiàn)的線程鎖有以下幾個(gè):
- OSSpinLock
- os_unfair_lock
- pthread_mutex
- dispatch_semaphore
- dispatch_queue(DISPATCH_QUEUE_SERIAL)
- NSLock
- NSRecursiveLock
- NSCondition
- NSConditionLock
- @synchronized
OSSpinLock
OSSpinLock叫做”自旋鎖”,等待鎖的線程會(huì)處于忙等(busy-wait)狀態(tài),一直占用著CPU資源
目前已經(jīng)不再安全,可能會(huì)出現(xiàn)優(yōu)先級(jí)反轉(zhuǎn)問(wèn)題
如果等待鎖的線程優(yōu)先級(jí)較高,它會(huì)一直占用著CPU資源,優(yōu)先級(jí)低的線程就無(wú)法釋放鎖。
os_unfair_lock
os_unfair_lock用于取代不安全的OSSpinLock ,從iOS10開(kāi)始才支持
從底層調(diào)用看,等待os_unfair_lock鎖的線程會(huì)處于休眠狀態(tài),并非忙等
需要導(dǎo)入頭文件#import <os/lock.h>
pthread_mutex
mutex叫做互斥鎖,等待鎖的線程會(huì)處于休眠狀態(tài)
需要導(dǎo)入頭文件#import <pthread.h>
dispatch_semaphore
semaphore叫做”信號(hào)量”
信號(hào)量的初始值,可以用來(lái)控制線程并發(fā)訪問(wèn)的最大數(shù)量
信號(hào)量的初始值為1,代表同時(shí)只允許1條線程訪問(wèn)資源,保證線程同步
@synchronized
@synchronized是對(duì)mutex遞歸鎖的封裝
源碼查看:objc4中的objc-sync.mm文件
@synchronized(obj)內(nèi)部會(huì)生成obj對(duì)應(yīng)的遞歸鎖,然后進(jìn)行加鎖、解鎖操作
iOS線程同步方案性能比較
性能從高到低排序
os_unfair_lock
OSSpinLock
dispatch_semaphore
pthread_mutex
dispatch_queue(DISPATCH_QUEUE_SERIAL)
NSLock
NSCondition
pthread_mutex(recursive)
NSRecursiveLock
NSConditionLock
@synchronized
atomic
-atomic用于保證屬性setter、getter的原子性操作,相當(dāng)于在getter和setter內(nèi)部加了線程同步的鎖
可以參考源碼objc4的objc-accessors.mm
它并不能保證使用屬性的過(guò)程是線程安全的
iOS中的讀寫(xiě)安全方案
- pthread_rwlock
等待鎖的線程會(huì)進(jìn)入休眠
- dispatch_barrier_async
這個(gè)函數(shù)傳入的并發(fā)隊(duì)列必須是自己通過(guò)dispatch_queue_cretate創(chuàng)建的
如果傳入的是一個(gè)串行或是一個(gè)全局的并發(fā)隊(duì)列,那這個(gè)函數(shù)便等同于dispatch_async函數(shù)的效果