OC底层原理探索之自定义读写锁

2,834 阅读3分钟

这是我参与8月更文挑战的第10天,活动详情查看:8月更文挑战

读写锁

读写锁实际是⼀种特殊的互斥锁,它把对共享资源的访问者划分成读者和写者,读者只对共享资源进⾏读访问,写者则需要对共享资源进⾏写操作。这种锁相对于⾃旋锁⽽⾔,能提⾼并发性,因为在多处理器系统中,它允许同时有多个读者来访问共享资源,最⼤可能的读者数为实际的逻辑CPU数。写者是排他性的,⼀个读写锁同时只能有⼀个写者或多个读者(与CPU数相关),但不能同时既有读者⼜有写者。在读写锁保持期间也是抢占失效的。 ​

如果读写锁当前没有读者,也没有写者,那么写者可以⽴刻获得读写锁,否则它必须⾃旋在那⾥,直到没有任何写者或读者。如果读写锁没有写者,那么读者可以⽴即获得该读写锁,否则读者必须⾃旋在那⾥,直到写者释放该读写锁。 ​

⼀次只有⼀个线程可以占有写模式的读写锁,但是可以有多个线程同时占有读模式的读写锁.正是因为这个特性,当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞.当读写锁在读加锁状态时,所有试图以读模式对它进⾏加锁的线程都可以得到访问权,但是如果线程希望以写模式对此锁进⾏加锁,它必须直到所有的线程释放锁. ​

通常,当读写锁处于读模式锁住状态时,如果有另外线程试图以写模式加锁,读写锁通常会阻塞随后的读模式锁请求,这样可以避免读模式锁⻓期占⽤,⽽等待的写模式锁请求⻓期阻塞。 ​

读写锁适合于对数据结构的读次数⽐写次数多得多的情况.因为,读模式锁定时可以共享,以写模式锁住时意味着独占,所以读写锁⼜叫共享-独占锁. ​

读写锁相关API

#include<pthread.h>
intpthread_rwlock_init(pthread_rwlock_t*restrictrwlock,constpthread_rwlockattr_t*restrictattr);
intpthread_rwlock_destroy(pthread_rwlock_t*rwlock)

成功则返回0,出错则返回错误编号.同互斥量一样,在释放读写锁占⽤的内存之前,需要先通过pthread_rwlock_destroy对读写锁进⾏清理⼯作,释放由init分配的资源.

#include<pthread.h>
intpthread_rwlock_rdlock(pthread_rwlock_t*rwlock);
intpthread_rwlock_wrlock(pthread_rwlock_t*rwlock);
intpthread_rwlock_unlock(pthread_rwlock_t*rwlock);

成功则返回0,出错则返回错误编号.以上这3个函数分别实现获取读锁,获取写锁和释放锁的操作.获取锁的两个函数是阻塞操作,同样,⾮阻塞的函数为:

#include<pthread.h>
intpthread_rwlock_tryrdlock(pthread_rwlock_t*rwlock);
intpthread_rwlock_trywrlock(pthread_rwlock_t*rwlock);

成功则返回0,出错则返回错误编号.⾮阻塞的获取锁操作,如果可以获取则返回0,否则返回错误的EBUSY. ​

GCD实现读写锁

思考:

  1. 多读单写
  2. 写和写互斥
  3. 读写互斥
  4. 写不能阻塞其他任务执行

写:可以使用栅栏函数dispatch_barriy_async 读:既然是多读那就是并发 可以使用并发队列 dispatch_async

// 多读
- (void)safeSetter: (NSString *)name time:(int)time {
    dispatch_barrier_async(self.safeQu, ^{
        sleep(time);
        [self.dict setValue:name forKey:@"test"];
        NSLog(@"写入 %@ - %@",self.dict[@"test"], [NSThread currentThread]);
    });
}
// 单写
- (NSString *)safeGetter {
    __block NSString * result;
    // 加个同步 保证在当前线程读取是正确的 不然result返回的是null
    dispatch_sync(self.safeQu, ^{
        result = self.dict[@"test"];
    });
    return result;
}

dispatch_sync不仅保证了在当前线程中,保证了先取值后返回的顺序。同时也保证了在同一个队列中,读写互斥。