读写锁是计算机程序的并发控制的一种同步机制,也称“共享-互斥锁”、多读者-单写者锁。读操作可并发重入,写操作是互斥的。
实现原理
两把互斥锁
使用两把互斥锁与一个整数计数器实现。计数器condition跟踪被阻塞的读线程。互斥锁rlock保护condition,供读者使用。互斥锁wlock 确保写操作互斥。
#import "JKRWLock.h"
#import <pthread/pthread.h>
pthread_mutex_t rlock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t wlock = PTHREAD_MUTEX_INITIALIZER;
static int condition = 0;
@implementation JKRWLock
//读者加锁
- (void)rLock {
pthread_mutex_lock(&rlock);
condition++;
if (condition == 1) {
pthread_mutex_lock(&wlock);
}
pthread_mutex_unlock(&rlock);
}
//读者解锁
- (void)rUnlock {
pthread_mutex_lock(&rlock);
condition--;
if (condition == 0) {
pthread_mutex_unlock(&wlock);
}
pthread_mutex_unlock(&rlock);
}
//写者加锁
- (void)wLock {
pthread_mutex_lock(&wlock);
}
//写者解锁
- (void)wUnlock {
pthread_mutex_unlock(&wlock);
}
@end
条件变量+互斥锁
可使用条件变量cond与普通的互斥锁rwlock、整型计数器readCount(表示正在读的个数)与布尔标志write(表示正在写)来实现读写锁。
#import "JKRWLock.h"
#import <pthread/pthread.h>
@interface JKRWLock ()
@property (nonatomic, assign) int readCount;
@property (nonatomic, assign, getter=isWriting) BOOL write;
@end
//读写锁
pthread_mutex_t rwlock = PTHREAD_MUTEX_INITIALIZER;
//条件变量
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
@implementation JKRWLock
//读者加锁
- (void)rLock {
pthread_mutex_lock(&rwlock);
while (self.isWriting) {
pthread_cond_wait(&cond, &rwlock);
}
self.readCount++;
pthread_mutex_unlock(&rwlock);
}
//读者解锁
- (void)rUnlock {
pthread_mutex_lock(&rwlock);
self.readCount--;
if (self.readCount == 0) {
//唤起一条写的线程
pthread_cond_signal(&cond);
}
pthread_mutex_unlock(&rwlock);
}
//写者加锁
- (void)wLock {
pthread_mutex_lock(&rwlock);
while (self.isWriting || self.readCount > 0) {
pthread_cond_wait(&cond, &rwlock);
}
self.write = YES;
pthread_mutex_unlock(&rwlock);
}
//写者解锁
- (void)wUnlock {
pthread_mutex_lock(&rwlock);
self.write = NO;
//唤起多个读的线程
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&rwlock);
}
@end
同步任务+栅栏
读数据
- (id)objectForKey:(NSString *)key {
__block id obj;
// 同步读取指定数据:
dispatch_sync(self.concurrent_queue, ^{
obj = [self.dataCenterDic objectForKey:key];
});
return obj;
}
写数据
- (void)setObject:(id)obj forKey:(NSString *)key {
// 异步栅栏调用设置数据:
dispatch_barrier_async(self.concurrent_queue, ^{
[self.dataCenterDic setObject:obj forKey:key];
});
}
总结
以上就是关于读写锁的实现原理以及它的一些使用方式。如果你有更好的实现方式,欢迎私信我。
网友评论