iOS 多线程与线程安全(二)

iOS 中实现线程安全

  实现线程安全可以通过加锁、单线程访问等方式。

        iOS 中常用的几种锁:

      os_unfair_lock

      pthread_mutex

        dispatch_semaphore

      NSLock

      NSRecursiveLock

      NSCondition

                  NSConditionLock

      @synchorized

          单线程访问:

      dispatch_queue(DISPATCH_QUEUE_SERIAL),串行队列

      dispatch_barrier_async

 

一、os_unfair_lock    

#import  <os/lock.h>

static os_unfair_lock _unfailLock; static int _osCount; - (void)unfailrLock { _unfailLock = OS_UNFAIR_LOCK_INIT; // 初始化锁 _osCount = 20; for (int i = 0; i < 20; i++) { dispatch_async(dispatch_get_global_queue(0, 0), ^{ [self unfailrLockBlock]; }); } } - (void)unfailrLockBlock { os_unfair_lock_lock(&_unfailLock); // 加锁 sleep(1); _osCount--; NSLog(@"os_unfair_lock %ld", (long)_osCount); os_unfair_lock_unlock(&_unfailLock); // 解锁 }

  

二、pthread_mutex

static pthread_mutex_t _mutexLock;

static int _mutexCount;

- (void)pthreadMutex {

    pthread_mutexattr_t attr;

    pthread_mutexattr_init(&attr);

    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT); // PTHREAD_MUTEX_RECURSIVE 递归锁

    pthread_mutex_init(&_mutexLock, &attr); // pthread_mutex_init(&_mutexLock, NULL);

    _mutexCount = 20;

    for (int i = 0; i < 20; i++) {

        dispatch_async(dispatch_get_global_queue(0, 0), ^{

            [self pthreadMutexBlock];

        });

    }

}

 

- (void)pthreadMutexBlock {

    pthread_mutex_lock(&_mutexLock);

    sleep(1);

    _mutexCount--;

    NSLog(@"pthread_mutex %ld", (long)_mutexCount);

    pthread_mutex_unlock(&_mutexLock);

}

  

三、dispatch_semaphore,当信号量小于1的时候,线程进入休眠等待。

static dispatch_semaphore_t _semaphore;
static int _semaphoreCount;
- (void)semaphore {
    _semaphore = dispatch_semaphore_create(1);
    _semaphoreCount = 20;
    for (int i = 0; i < 20; i++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [self semaphoreBlock];
        });
    }
}

- (void)semaphoreBlock {
    dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
    sleep(1);
    _semaphoreCount--;
    NSLog(@"semaphore %ld", (long)_semaphoreCount);
    dispatch_semaphore_signal(_semaphore);
}

  

四、NSLock  对pthread_mutex 普通类型锁的封装,NSRecursiveLock pthread_mutex 递归类型锁的封装。递归锁,同一个线程可以对一个锁多次加锁。

static NSLock *_nslock;
static int _lockCount;
- (void)nslock {
    _nslock = [[NSLock alloc] init];
    _lockCount = 20;
    for (int i = 0; i < 20; i++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [self nslockBlock];
        });
    }
}

- (void)nslockBlock {
    [_nslock lock];
    sleep(1);
    _lockCount--;
    NSLog(@"nslock %ld", (long)_lockCount);
    [_nslock unlock];
}

  

五、NSCondition、NSConditionLock 是对 pthread_mutex 的 condition 属性封装。

static NSCondition *_cond;
static int _condCount;
- (void)condition {
    _cond = [[NSCondition alloc] init];
    _condCount = 10;
    for (int i = 0; i < 15; i++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [self reduce];
        });
    }

    for (int i = 0; i < 10; i++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [self add];
        });
    }
}

- (void)reduce {
    [_cond lock];
    if (_condCount == 0) {
        [_cond wait];
    }
    sleep(1);
    _condCount--;
    NSLog(@"reduce %ld", (long)_condCount);
    [_cond unlock];
}

- (void)add {
    [_cond lock];
    if (_condCount >= 0) {
        [_cond signal];   // 一次singnal只能唤醒一个在等待condition的线程,如果想唤醒多个可使用[_cond broadcast];
    }
    sleep(1);
    _condCount++;
    NSLog(@"add %ld", (long)_condCount);
    [_cond unlock];
}

  

六、@synchorized,runtime 会给 synchorized 调用的每一个对象分配一个递归锁并存储在哈希表中,因此效率比较低不建议使用。  

  @synchorized(nil) 会加锁失败。

 

七、pthread_rwlock 用于文件读写操作的锁,pthread_rwlock_rdlock(&lock) 读操作加锁,临界区(被加锁的代码)并发执行,pthread_rwlock_wrlock(&lock))写操作加锁,临界区只会串行执行

static pthread_rwlock_t _rwlock = PTHREAD_RWLOCK_INITIALIZER;
static int _rwlockCount;
- (void)pthreadRWLock {
    _rwlockCount = 10;
    for (int i = 0; i < 15; i++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [self rwRead];
        });
    }

    for (int i = 0; i < 2; i++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [self rwWrite];
        });
    }
}

- (void)rwRead {
    pthread_rwlock_rdlock(&_rwlock);
    sleep(1);
    NSLog(@"pthread_rw read %ld", (long)_rwlockCount);
    pthread_rwlock_unlock(&_rwlock);
}

- (void)rwWrite {
    pthread_rwlock_wrlock(&_rwlock);
    sleep(1);
    _rwlockCount++;
    NSLog(@"pthread_rw write %ld", (long)_rwlockCount);
    pthread_rwlock_unlock(&_rwlock);
}

输出
2020-06-08 22:46:01.137977+0800 多线程[7019:829191] pthread_rw read 10
    2020-06-08 22:46:01.137977+0800 多线程[7019:829189] pthread_rw read 10
    2020-06-08 22:46:01.137978+0800 多线程[7019:829194] pthread_rw read 10
    2020-06-08 22:46:01.137978+0800 多线程[7019:829190] pthread_rw read 10
    2020-06-08 22:46:01.137989+0800 多线程[7019:829195] pthread_rw read 10
    2020-06-08 22:46:01.137977+0800 多线程[7019:829188] pthread_rw read 10
    2020-06-08 22:46:01.138022+0800 多线程[7019:829256] pthread_rw read 10
    2020-06-08 22:46:01.138021+0800 多线程[7019:829252] pthread_rw read 10
    2020-06-08 22:46:01.138022+0800 多线程[7019:829257] pthread_rw read 10
    2020-06-08 22:46:01.138024+0800 多线程[7019:829255] pthread_rw read 10
    2020-06-08 22:46:01.138022+0800 多线程[7019:829254] pthread_rw read 10
    2020-06-08 22:46:01.138028+0800 多线程[7019:829253] pthread_rw read 10
    2020-06-08 22:46:01.138047+0800 多线程[7019:829258] pthread_rw read 10
    2020-06-08 22:46:01.138048+0800 多线程[7019:829259] pthread_rw read 10
    2020-06-08 22:46:01.138053+0800 多线程[7019:829260] pthread_rw read 10
    2020-06-08 22:46:02.143706+0800 多线程[7019:829261] pthread_rw write 11
    2020-06-08 22:46:03.144493+0800 多线程[7019:829262] pthread_rw write 12

  

 

七、atomic、自旋锁与互斥锁

atomic:原子性,当一个属性被标记为atomic的时候,get和set方法通过加锁的方法实现原子性,iOS手机上一般不使用atomic属性。

自旋锁:当线程获取不到锁的时候,线程处于忙等状态(类似while循环),cpu处于忙等状态。

互斥锁:当线程获取不到锁的时候,线程进入休眠状态,cpu 资源得到释放。目前 iOS 的锁基本都是互斥锁。

 

 

 

          

posted @ 2020-06-08 22:51  一坨☁️  阅读(204)  评论(0编辑  收藏  举报