在上一篇文章中,我們主要了解了多線程安全隱患,以及它的解決方案。其中,我們有了解到自旋鎖和互斥鎖,這兩種經(jīng)常用到的鎖。這里有一個(gè)大致的總結(jié),看看這兩個(gè)鎖在什么情況下比較合適:
1、什么情況使用自旋鎖比較劃算?
預(yù)計(jì)線程等待鎖的時(shí)間很短
加鎖的代碼(臨界區(qū))經(jīng)常被調(diào)用,但競(jìng)爭(zhēng)情況很少發(fā)生
CPU資源不緊張
多核處理器
什么情況使用互斥鎖比較劃算?
2、預(yù)計(jì)線程等待鎖的時(shí)間較長(zhǎng)
單核處理器
臨界區(qū)有IO操作
臨界區(qū)代碼復(fù)雜或者循環(huán)量大
臨界區(qū)競(jìng)爭(zhēng)非常激烈
接下來,我們?cè)倏戳硪粋€(gè)知識(shí)點(diǎn),是關(guān)于讀寫安全方面的知識(shí),首先我們來認(rèn)識(shí)下atomic這個(gè)修飾符,在iOS這個(gè)修飾符的作用就是保證屬性setter、getter的原子性操作,相當(dāng)于在getter和setter內(nèi)部加了線程同步的鎖,它能保證在單個(gè)讀和寫的過程中是安全的,但是它并不能保證使用屬性的過程是線程安全的。
這里,我們就針對(duì)這個(gè)使用屬性過程的線程安全問題來看下,首先,我們需要了解方案的具體要求。大致如下:
1、同一時(shí)間,只能有1個(gè)線程進(jìn)行寫的操作。
2、同一時(shí)間,允許有多個(gè)線程進(jìn)行讀的操作。
3、同一時(shí)間,不允許既有寫的操作,又有讀的操作。
總結(jié)一句話的意思,就是“多讀單寫”,就是可以多條線程同時(shí)讀取,但是在寫入的時(shí)候,只能有一條線程在操作這個(gè)屬性。iOS的常用實(shí)現(xiàn)方案有:
1、pthread_rwlock:讀寫鎖
2、dispatch_barrier_async:異步柵欄
先來看看C語(yǔ)言中的讀寫鎖pthread_rwlock的使用:
- (void)demo {
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);
sleep(1);
NSLog(@"read");
pthread_rwlock_unlock(&_lock);
}
- (void)write
{
pthread_rwlock_wrlock(&_lock);
sleep(1);
NSLog(@"write");
pthread_rwlock_unlock(&_lock);
}
- (void)dealloc {
pthread_rwlock_destroy(&_lock);
}
打印結(jié)果如下圖:

我們可以很清楚的發(fā)現(xiàn),只有在read操作的時(shí)候,是有多條線程同時(shí)打印的,任何write操作,都是會(huì)有1秒鐘的間隔。
接下來,我們來看看異步柵欄操作:
- (void)demo {
dispatch_queue_t queue = dispatch_queue_create("rw_queue", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
[self read];
});
dispatch_async(queue, ^{
[self read];
});
dispatch_async(queue, ^{
[self read];
});
dispatch_barrier_async(queue, ^{
[self write];
});
};
}
- (void)read {
sleep(1);
NSLog(@"read");
}
- (void)write
{
sleep(1);
NSLog(@"write");
}
打印結(jié)果如下:

也是我們所希望看到的結(jié)果。
不過這里有個(gè)必要的點(diǎn),我們需要了解下,就是創(chuàng)建的queue必須是自定義的DISPATCH_QUEUE_CONCURRENT,如果是自定義串行隊(duì)列或者直接使用全局并發(fā)隊(duì)列,那么dispatch_barrier_async這個(gè)函數(shù)等同于dispatch_async!
以上就是這次對(duì)多線程知識(shí)點(diǎn)總結(jié)的補(bǔ)充內(nèi)容!