欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

iOS開發(fā)常用線程安全鎖

 更新時間:2022年07月26日 10:48:14   作者:懶的問蒼天  
這篇文章主要為大家介紹了iOS開發(fā)常用線程安全鎖示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

正文

多線程開發(fā),就會有資源搶占的情況,導致出現(xiàn)我們意想不到的數(shù)據(jù)問題,我們就需要對數(shù)據(jù)進行加鎖,已保證線程安全.

鎖主要分為兩大類自旋鎖和互斥鎖。

  • 自旋鎖:自旋鎖已經(jīng)被別的執(zhí)行單元保持,調(diào)用者就一直循環(huán)在那里看是否該自旋鎖的保持者已經(jīng)釋放了鎖,因此是一種忙等待。自旋鎖避免了線程上下文切換的調(diào)度開銷,因此對于線程只會阻塞很短的時間是很高效的,但是對于比較長時間的阻塞也是比較消耗CPU的。(線程忙等)
  • 互斥鎖:如果資源已經(jīng)被占用,資源申請者只能進入睡眠狀態(tài)。有上下文的切換(主動出讓時間片, 線程休眠, 等待下一次喚醒)、CPU的搶占、信號的發(fā)送等開銷。(線程閑等)

原子屬性

我們創(chuàng)建屬性一般都會設置屬性為非原子屬性noatomic, 因為原子屬性atomic會有額外的加鎖開銷,那如果我們創(chuàng)建屬性使用原子屬性atomic,它能保證property是線程安全的嗎?

#import "ViewController.h"
@interface ViewController ()
@property (atomic ,assign) int count;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.count = 0;
    [self test_atomic];
}
- (void)test_atomic {
    // self.count初始值是10
    for (int i = 0; i < 10; i ++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            self.count ++;
            NSLog(@"%d",self.count);
        });
    }
}
@end

從上面我們可以看到原子屬性atomic不能保證數(shù)據(jù)的線程安全.下面我們從源碼進行分析:在屬性的getter/setter方法調(diào)用的底層atomic和nonatomic有什么區(qū)別。先看看setter方法:objc_setProperty

void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy) {
    bool copy = (shouldCopy && shouldCopy != MUTABLE_COPY);
    bool mutableCopy = (shouldCopy == MUTABLE_COPY);
    reallySetProperty(self, _cmd, newValue, offset, atomic, copy, mutableCopy);
}
void objc_setProperty_atomic(id self, SEL _cmd, id newValue, ptrdiff_t offset{
    reallySetProperty(self, _cmd, newValue, offset, true, false, false);
}
void objc_setProperty_nonatomic(id self, SEL _cmd, id newValue, ptrdiff_t offset) {
    reallySetProperty(self, _cmd, newValue, offset, false, false, false);
}
void objc_setProperty_atomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset) {
    reallySetProperty(self, _cmd, newValue, offset, true, true, false);
}
void objc_setProperty_nonatomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset) {
    reallySetProperty(self, _cmd, newValue, offset, false, true, false);
}

我們可以看到都是調(diào)用的reallySetProperty方法,atomic第五個參數(shù)為true,nonatomic為false, copy第六個參數(shù)為true, mutableCopy第七個參數(shù)為true.

static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy) {
    if (offset == 0) {
        object_setClass(self, newValue);
        return;
    }
    id oldValue;
    id *slot = (id*) ((char*)self + offset);
    if (copy) {
        newValue = [newValue copyWithZone:nil];
    } else if (mutableCopy) {
        newValue = [newValue mutableCopyWithZone:nil];
    } else {
        if (*slot == newValue) return;
        newValue = objc_retain(newValue);
    }
    if (!atomic) {
        oldValue = *slot;
        *slot = newValue;
    } else {
        spinlock_t& slotlock = PropertyLocks[slot];
        slotlock.lock();
        oldValue = *slot;
        *slot = newValue;        
        slotlock.unlock();
    }
    objc_release(oldValue);
}

copy和mutableCopy使用copyWithZone進行新值的copy,其他使用objc_retain增加引用計數(shù).nonatomic直接進行賦值;atomic會使用spinlock_t在賦值之前加鎖,賦值之后解鎖. 我們再來看看getter方法:objc_getProperty

id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
    if (offset == 0) {
        return object_getClass(self);
    }
    // Retain release world
    id *slot = (id*) ((char*)self + offset);
    if (!atomic) return *slot;    
    // Atomic retain release world
    spinlock_t& slotlock = PropertyLocks[slot];
    slotlock.lock();
    id value = objc_retain(*slot);
    slotlock.unlock();
    // for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
    return objc_autoreleaseReturnValue(value);
}

我們可以看到nonatomic直接返回,atomic在取值前加鎖,取值后解鎖,再返回值.

那么原子屬性atomic在getter/setter底層有加鎖解鎖操作,為什么不能保證線程安全的呢?
因為原子屬性atomic鎖住資源的范圍不夠大。在self.count --;的時候,既有getter也有setter,可能就出現(xiàn)當getter的時候還沒有return出去就被其它線程setter。

OSSpinLock - 自旋鎖

OSSpinLock 在iOS10之后被移除了。  被移除的原因是它有一個bug:優(yōu)先級反轉(zhuǎn)。

優(yōu)先級反轉(zhuǎn):當多個線程有優(yōu)先級的時候,有一個優(yōu)先級較低的線程先去訪問了資源,并是有了OSSpinLock對資源加鎖,又來一個優(yōu)先級較高的線程去訪問了這個資源,這個時候優(yōu)先級較高的線程就會一直占用cpu的資源,導致優(yōu)先級較低的線程沒辦法與較高的線程爭奪cpu的時間,最后導致最先被優(yōu)先級較低的線程鎖住的資源遲遲不能被釋放,從而造成優(yōu)先級反轉(zhuǎn)的bug。

所以 OSSpinLock使用限制:必須保證所有訪問同一資源的線程處于優(yōu)先級平等的時候,才可以使用。

OSSpinLock已被蘋果放棄了,大家也可以放棄它,蘋果設計了os_unfair_lock來代替OSSpinLock。

os_unfair_lock - 互斥鎖

iOS10之后開始支持,os_unfair_lock 在os庫中,使用之前需要導入頭文件<os/lock.h>。

#import "ViewController.h"
#import <os/lock.h>
@interface ViewController ()
@property (nonatomic ,assign) int count;
@property (nonatomic ,assign) os_unfair_lock unfairLock;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.count = 0;
    self.unfairLock = OS_UNFAIR_LOCK_INIT; // 初始化鎖
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    for (int i = 0; i<10; i++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            os_unfair_lock_lock(&_unfairLock); // 加鎖
            self.count ++;
            NSLog(@"%d",self.count);
            os_unfair_lock_unlock(&_unfairLock); // 解鎖
        });
    }
}
@end

NSLock - 互斥鎖

NSLock - Foundation框架內(nèi)部的??,使用起來非常方便,基于pthroad_mutex封裝而來,是一把互斥非遞歸鎖。因為OC的Foundation框架是非開源的,所以我們查看swift的Foundation框架,來查看其源碼實現(xiàn),原理是相同的

#if os(Windows)
#elseif CYGWIN
#else
private typealias _MutexPointer = UnsafeMutablePointer<pthread_mutex_t>
private typealias _RecursiveMutexPointer = UnsafeMutablePointer<pthread_mutex_t>
private typealias _ConditionVariablePointer = UnsafeMutablePointer<pthread_cond_t>
#endif
open class NSLock: NSObject, NSLocking {
    internal var mutex = _MutexPointer.allocate(capacity: 1)
#if os(macOS) || os(iOS) || os(Windows)
    private var timeoutCond = _ConditionVariablePointer.allocate(capacity: 1)
    private var timeoutMutex = _MutexPointer.allocate(capacity: 1)
#endif
    public override init() {
#if os(Windows)
#else
        pthread_mutex_init(mutex, nil)
#if os(macOS) || os(iOS)
        pthread_cond_init(timeoutCond, nil)
        pthread_mutex_init(timeoutMutex, nil)
#endif
#endif
    }
    deinit {
#if os(Windows)
#else
        pthread_mutex_destroy(mutex)
#endif
        mutex.deinitialize(count: 1)
        mutex.deallocate()
#if os(macOS) || os(iOS) || os(Windows)
        deallocateTimedLockData(cond: timeoutCond, mutex: timeoutMutex)
#endif
    }
    open func lock() {
#if os(Windows)
#else
        pthread_mutex_lock(mutex)
#endif
    }
    open func unlock() {
#if os(Windows)
#else
        pthread_mutex_unlock(mutex)
#if os(macOS) || os(iOS)
        // Wakeup any threads waiting in lock(before:)
        pthread_mutex_lock(timeoutMutex)
        pthread_cond_broadcast(timeoutCond)
        pthread_mutex_unlock(timeoutMutex)
#endif
#endif
    }
    ...
}

我們可以起內(nèi)部是對pthread_mutex_t的封裝

  • 構造方法 init()就是調(diào)用了pthread的pthread_mutex_init(mutex, nil)方法
  • 析構方法 deinit就是調(diào)用了pthread的pthread_mutex_destroy(mutex)方法
  • 加鎖方法 lock()就是調(diào)用了pthread的pthread_mutex_lock(mutex)方法
  • 解鎖方法 unlock()就是調(diào)用了pthread的pthread_mutex_unlock(mutex)方法

在pthread_mutex中可以通過pthread_mutexattr_settype(attrs, Int32(PTHREAD_MUTEX_RECURSIVE))來設置鎖為遞歸鎖,這里并沒有設置,所以NSLock不是一把遞歸鎖!

NSCondition - 互斥鎖

我們通過查看swift foundation 源碼 可以看到其和NSLock類似,也是對pthread_mutex_t的封裝,相比于NSLock,NSCondition多了幾個API:

    open func wait() {
        pthread_cond_wait(cond, mutex)
    }
    open func wait(until limit: Date) -> Bool {
        guard var timeout = timeSpecFrom(date: limit) else {
            return false
        }
        return pthread_cond_timedwait(cond, mutex, &timeout) == 0
    }
    open func signal() {
        pthread_cond_signal(cond)
    }
    open func broadcast() {
        pthread_cond_broadcast(cond)
    }
  • (void)wait 阻塞當前線程,使線程進入休眠,等待喚醒信號。調(diào)用前必須已加鎖。
  • (void)waitUntilDate 阻塞當前線程,使線程進入休眠,等待喚醒信號或者超時。調(diào)用前必須已加鎖。
  • (void)signal 喚醒一個正在休眠的線程,如果要喚醒多個,需要調(diào)用多次。如果沒有線程在等待,則什么也不做。調(diào)用前必須已加鎖。
  • (void)broadcast 喚醒所有在等待的線程。如果沒有線程在等待,則什么也不做。調(diào)用前必須已加鎖。
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic ,assign) int count;
@property (nonatomic ,strong) NSCondition *iCondition;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.count = 0;
    self.iCondition = [[NSCondition alloc] init]; // 初始化鎖
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self nscondition_test];
}
#pragma mark -- NSCondition
- (void)nscondition_test {
    // 生產(chǎn)
    for (int i = 0; i < 50; i ++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [self my_production];
        });
    }
    // 消費
    for (int i = 0; i < 100; i ++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [self my_consumption];
        });
    }
}
- (void)my_production {
    [self.iCondition lock];
    self.count ++;
    NSLog(@"生產(chǎn)了一個產(chǎn)品,現(xiàn)有產(chǎn)品 : %d個",self.count);
    [self.iCondition signal]; // 喚醒一個wait正在休眠的線程
    [self.iCondition unlock];
}
- (void)my_consumption {
    [self.iCondition lock]; 
    while (self.count == 0) { // 這里使用 if 會出現(xiàn)現(xiàn)有產(chǎn)品是負數(shù)的情況
        [self.iCondition wait]; // 阻塞當前線程,使線程進入休眠,等待喚醒信號signal
    }
    self.count --;
    NSLog(@"消費了一個產(chǎn)品,現(xiàn)有產(chǎn)品: %d個",self.count);
    [self.iCondition unlock];
}
@end

注意??:pthread_mutex 存在虛假喚醒的情況,一個signl喚醒多個wait,不是預期的signal : wait = 1:1效果。 在編碼過程中可以通過while條件判斷,使被喚醒的線程,陷入while循環(huán)中,從而解決此問題。

NSConditionLock - 互斥鎖

NSConditionLock是基于NSCondition的封裝。目的是讓NSConditionLock自帶條件探測

open class NSConditionLock : NSObject, NSLocking {
    internal var _cond = NSCondition()
    ......
    open func lock(whenCondition condition: Int) {
        let _ = lock(whenCondition: condition, before: Date.distantFuture)
    }
    open func `try`() -> Bool {
        return lock(before: Date.distantPast)
    }
    open func tryLock(whenCondition condition: Int) -> Bool {
        return lock(whenCondition: condition, before: Date.distantPast)
    }
    open func unlock(withCondition condition: Int) {
        _cond.lock()
        _thread = nil
        _value = condition
        _cond.broadcast()
        _cond.unlock()
    }
    ...
}
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic ,strong) NSConditionLock *iConditionLock;
@end
@implementation ViewController
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self conditonLock_test];
}
#pragma mark -- NSConditionLock
- (void)conditonLock_test {
    self.iConditionLock = [[NSConditionLock alloc] initWithCondition:3];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        [self.iConditionLock lockWhenCondition:3];
        NSLog(@"1");
        [self.iConditionLock unlockWithCondition:2];
    });
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        [self.iConditionLock lockWhenCondition:2];
        NSLog(@"2");
        [self.iConditionLock unlockWithCondition:1];
    });
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        [self.iConditionLock lockWhenCondition:1];
        NSLog(@"3");
        [self.iConditionLock unlockWithCondition:0];
    });
}
@end
// 線程任務的執(zhí)行順序:1 2 3

NSConditionLock能夠達到控制線程執(zhí)行任務順序的目的。

NSRecursiveLock

遞歸鎖:同一時刻只能被一條線程所擁有。 NSRecursiveLock是基于pthread的封裝,并設置了遞歸屬性。

open class NSRecursiveLock: NSObject, NSLocking {
    internal var mutex = _RecursiveMutexPointer.allocate(capacity: 1)
#if os(macOS) || os(iOS) || os(Windows)
    private var timeoutCond = _ConditionVariablePointer.allocate(capacity: 1)
    private var timeoutMutex = _MutexPointer.allocate(capacity: 1)
#endif
    public override init() {
        super.init()
#if CYGWIN
        var attrib : pthread_mutexattr_t? = nil
#else
        var attrib = pthread_mutexattr_t()
#endif
        withUnsafeMutablePointer(to: &attrib) { attrs in
            pthread_mutexattr_init(attrs)
            // 設置遞歸屬性
            pthread_mutexattr_settype(attrs, Int32(PTHREAD_MUTEX_RECURSIVE))
            pthread_mutex_init(mutex, attrs)
        }
        pthread_cond_init(timeoutCond, nil)
    }

NSConditionLock是一把遞歸鎖,可遞歸加鎖解鎖(可適用于遞歸函數(shù))

通過PTHREAD_MUTEX_RECURSIVE來設置鎖為遞歸鎖。當鎖為遞歸鎖的時候,它的使用場景為單個線程中的遞歸調(diào)用。

#import "ViewController.h"
@interface ViewController ()
@property (nonatomic ,assign) int count;
@property (nonatomic ,strong) NSRecursiveLock *iRecursiveLock;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.count = 0;
    self.iRecursiveLock = [[NSRecursiveLock alloc] init]; // 初始化鎖
    [self recursiveTest]; // 遞歸鎖案例
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    for (int i = 0; i<10; i++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [self recursiveLock_test]; 
        });
    }
}
#pragma mark -- NSRecursiveLock
-(void)recursiveLock_test {
    [self.iRecursiveLock lock];
    self.count ++;
    NSLog(@"%d",self.count);
    [self.iRecursiveLock unlock];
}
- (void)recursiveTest {
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        static void (^recursiveMethod)(int);
        recursiveMethod = ^(int value){
            if (value > 0) {
                [self.iRecursiveLock lock];
                NSLog(@"%d",value);
                recursiveMethod(value - 1);
                [self.iRecursiveLock unlock];
            }
        };
        recursiveMethod(10);
    });
}
@end

如果在不同線程進行遞歸調(diào)用的話,會出現(xiàn)問題,把recursiveTest方法放到for循環(huán)里

- (void)recursiveTest {
    for (int i = 0; i < 5; i++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            static void (^recursiveMethod)(int);
            recursiveMethod = ^(int value){
                if (value > 0) {
                    [self.iRecursiveLock lock];
                    NSLog(@"%d",value);
                    recursiveMethod(value - 1);
                    [self.iRecursiveLock unlock];
                }
            };
            recursiveMethod(10);
        });
    }
}

此時代碼會因為子線程相互等待資源而造成線程死鎖。

@synchronized

@synchronized不管你幾條線程,不管你是否遞歸調(diào)用,它都支持,是我們最常用的一把鎖,雖然都在詬病其性能問題,可是在真機條件下測試其性能,和其他鎖并沒有那么明顯的差別。

#import "ViewController.h"
@interface ViewController ()
@property (nonatomic ,assign) int count;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.count = 0;
    [self synchronized_test]; // synchronized案例
}
- (void)synchronized_test {
    for (int i=0; i<5; i++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            static void (^recursiveMethod)(int);
            recursiveMethod = ^(int value){
                if (value > 0) {
                    @synchronized(self) {
                         NSLog(@"%d",value);
                         recursiveMethod(value - 1);
                    }
                }
            };
            recursiveMethod(10);
        });
    }
}
@end

@synchronized(obj)指令使用的obj為該鎖的唯一標識,只有當標識相同時,才為滿足互斥。, @synchronized還是個遞歸可重入鎖,如下代碼所示:

   NSObject *obj = [[NSObject alloc] init];
   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
        @synchronized(obj){
            NSLog(@"1開始");
            @synchronized (obj) {
                NSLog(@"2開始");
                @synchronized (obj) {
                    NSLog(@"3");
                }
                NSLog(@"2完成");
            }
            NSLog(@"1結束");
        }
    });

@synchronized是個遞歸互斥鎖,同一個線程可以重復獲得這個鎖并進入執(zhí)行執(zhí)行塊里面的代碼而不會導致死鎖。

@synchronized的優(yōu)點:不需要在代碼中顯式的創(chuàng)建鎖對象,便可以實現(xiàn)鎖的機制;遞歸互斥,同一個線程可以重復進入而不導致死鎖。

@synchronized的缺點:效率低(在真機上不見得效率那么低)。@synchronized塊會隱式的添加一個異常處理例程來保護代碼,該處理例程會在異常拋出的時候自動的釋放互斥鎖,這會增加額外的開銷。同時為了實現(xiàn)遞歸互斥可重入,底層使用的是遞歸鎖加上復雜的業(yè)務邏輯,也增加了不少的消耗。

@synchronized加鎖需要一個對象參數(shù),在選著對象參數(shù)的時候要特別注意不能讓對象參數(shù)為nil,否則加鎖無效。

Semaphore信號量

同樣的信號量也可以解決線程安全問題,相關內(nèi)容請查閱GCD篇章,主要是控制并發(fā)數(shù)量,來實現(xiàn)線程安全

#pragma mark -- dispatch_semaphore_t
- (void)dispatch_semaphore_t_test {
    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"任務1");
        dispatch_semaphore_signal(sem);
    });
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"任務2");
        dispatch_semaphore_signal(sem);
    });
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"任務3");
    });
}

pthread_mutex

純C的鎖,需要我們自己進行對象的內(nèi)存管理,前面有些鎖就是對齊進行的封裝.

#pragma mark -- pthread_mutex
- (void)pthread_mutex_test {
    //非遞歸加鎖
    pthread_mutex_t lock0;
    pthread_mutex_init(&lock0, NULL);
    pthread_mutex_lock(&lock0);
    // 鎖住的資源...
    pthread_mutex_unlock(&lock0);
    pthread_mutex_destroy(&lock0); // c對象,需要自己釋放資源
    //遞歸加鎖
    pthread_mutex_t lock;
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); // 設置遞歸屬性
    pthread_mutex_init(&lock, &attr);
    pthread_mutexattr_destroy(&attr);
    pthread_mutex_lock(&lock);
    // 鎖住的資源...
    pthread_mutex_unlock(&lock);
    pthread_mutex_destroy(&lock); // c對象,需要自己釋放資源
}

讀寫鎖

讀寫鎖實際是一種特殊的自旋鎖,它把對共享資源的訪問者劃分成讀者和寫者,讀者只對共享資源進行讀訪問,寫者則需要對共享資源進行寫操作。這種鎖相對于自旋鎖而言,能提高并發(fā)性,因為在多處理器系統(tǒng)中,它允許同時有多個讀者來訪問共享資源,最大可能的讀者數(shù)為實際的邏輯CPU數(shù)。寫者是排他性的,一個讀寫鎖同時只能有一個寫者或多個讀者(與CPU數(shù)相關),但不能同時既有讀者又有寫者。在讀寫鎖保持期間也是搶占失效的。

如果讀寫鎖當前沒有讀者,也沒有寫者,那么寫者可以立刻獲得讀寫鎖,否則它必須自旋在那里,直到?jīng)]有任何寫者或讀者。如果讀寫鎖沒有寫者,那么讀者可以立即獲得該讀寫鎖,否則讀者必須自旋在那里,直到寫者釋放該讀寫鎖。

讀寫鎖可以實現(xiàn)多讀單寫功能(讀讀并發(fā)、讀寫互斥、寫寫互斥) 我們通過GCD的柵欄函數(shù)實現(xiàn)的一個簡單讀寫鎖案例:

#import "ViewController.h"
@interface ViewController ()
@property (nonatomic ,strong) dispatch_queue_t iQueue;
@property (nonatomic ,strong) NSMutableDictionary *dataDic;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.iQueue = dispatch_queue_create("AnAn", DISPATCH_QUEUE_CONCURRENT);
    self.dataDic = [NSMutableDictionary new];
    [self my_write: @"我是寫的東西"];
}
- (void)test {
    for (int i = 0; i < 10; i ++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [self my_read];
        });
    }
}
#pragma mark -- 讀寫鎖
- (NSString *)my_read {
    // 異步讀取
    __block NSString *ret;
    dispatch_sync(self.iQueue, ^{
        // 讀取的代碼
        ret = self.dataDic[@"name"];
    });
    NSLog(@"%@",ret);
    return ret;
}
- (void)my_write: (NSString *)name {
    // 寫操作
    dispatch_barrier_async(self.iQueue, ^{
        [self.dataDic setObject:name forKey:@"name"];
    });
}

以上就是iOS開發(fā)常用線程安全鎖的詳細內(nèi)容,更多關于iOS線程安全鎖的資料請關注腳本之家其它相關文章!

相關文章

  • iOS實現(xiàn)循環(huán)滾動公告欄

    iOS實現(xiàn)循環(huán)滾動公告欄

    這篇文章主要為大家詳細介紹了iOS實現(xiàn)循環(huán)滾動公告欄,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-03-03
  • iOS?Segment帶滑動條切換效果

    iOS?Segment帶滑動條切換效果

    這篇文章主要為大家詳細介紹了iOS?Segment帶滑動條切換,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • iOS中的通知機制

    iOS中的通知機制

    網(wǎng)上經(jīng)常說iOS的通知機制是使用了觀察者模式,里面有兩個角色,其一是poster(發(fā)送者),另一個是observer(接受信息的訂閱者)。接下來通過本文給大家介紹iOS中的通知機制,感興趣的朋友一起學習吧
    2016-04-04
  • iOS基于UIScrollView實現(xiàn)滑動引導頁

    iOS基于UIScrollView實現(xiàn)滑動引導頁

    這篇文章主要為大家詳細介紹了iOS基于UIScrollView實現(xiàn)滑動引導頁的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • iOS Crash文件分析方法匯總

    iOS Crash文件分析方法匯總

    今天跟大家一起聊聊iOSCrash文件的幾種分析方法,都是平時比較常用的,有需要的小伙伴可以參考下
    2017-11-11
  • iOS中sqlite數(shù)據(jù)庫的原生用法

    iOS中sqlite數(shù)據(jù)庫的原生用法

    這篇文章主要為大家詳細介紹了iOS中sqlite數(shù)據(jù)庫的原生用法,sqlite數(shù)據(jù)庫相信各位早已耳聞,非常輕巧的一個數(shù)據(jù)庫,數(shù)據(jù)庫僅一個文件,即建即用,感興趣的小伙伴們可以參考一下3
    2016-05-05
  • iOS開發(fā)tips-UINavigationBar的切換效果

    iOS開發(fā)tips-UINavigationBar的切換效果

    這篇文章主要為大家詳細介紹了iOS開發(fā)tips-UINavigationBar的切換效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • iOS常用加密算法介紹和代碼實踐

    iOS常用加密算法介紹和代碼實踐

    這篇文章主要為大家詳細介紹了iOS常用加密算法介紹和代碼實踐,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-08-08
  • iOS實現(xiàn)手勢解鎖操作

    iOS實現(xiàn)手勢解鎖操作

    這篇文章主要為大家詳細介紹了iOS實現(xiàn)手勢解鎖操作功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-03-03
  • iOS開發(fā)TableView網(wǎng)絡請求及展示預加載實現(xiàn)示例

    iOS開發(fā)TableView網(wǎng)絡請求及展示預加載實現(xiàn)示例

    這篇文章主要為大家介紹了iOS開發(fā)TableView網(wǎng)絡請求及展示預加載實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07

最新評論