在上篇文章中已经讨论了iOS
中多线程方案, 本文章主要记录多线程的同步方案、文件的多读单写操作.
先附上demo地址
当多个线程同时访问同一块资源时, 容易引发数据错乱和数据安全问题, 为了解决这个问题, 引入锁的概念.
自旋锁和互斥锁
自旋锁: 如果资源被占用, 调用者会一直循环.
互斥锁: 如果资源被占用, 资源申请者就会进入休眠状态.
一. 多线程中的锁
iOS中的锁有OSSpinLock
os_unfair_lock
pthread_mutex
dispatch_semaphore
NSLock
NSRecursiveLock
NSCondition
NSConditionLock
@synchronized
等, 本片文章会对上诉锁做简单的应用以及讲解.
demo中已经对锁做了笔记.
二. 文件的多读单写
同一时间, 只能允许一个线程对文件进行写操作.
同一时间, 允许多个线程对文件进行读操作.
文件的多读单写方案有pthread_rwlock_t
和dispatch_barrier_async
两种方案.
pthread_rwlock_t方案
@interface YYFilePThreadRwlock()
@property (nonatomic ,assign) pthread_rwlock_t lock;
@end
@implementation YYFilePThreadRwlock
- (void)dealloc {
pthread_rwlock_destroy(&_lock);
}
- (instancetype)init {
if (self = [super init]) {
// 初始化锁
pthread_rwlock_init(&_lock, NULL);
}
return self;
}
- (void)readWriteTest {
for (int i = 0; i < 3; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self writeFile];
[self readFile];
});
}
}
- (void)readFile {
// 加锁
pthread_rwlock_rdlock(&_lock);
sleep(1);
NSLog(@"读文件--%@", [NSThread currentThread]);
// 解锁
pthread_rwlock_unlock(&_lock);
}
- (void)writeFile {
// 加锁
pthread_rwlock_wrlock(&_lock);
sleep(1);
NSLog(@"写文件--%@", [NSThread currentThread]);
// 解锁
pthread_rwlock_unlock(&_lock);
}
@end
执行结果如下:
2018-09-04 16:33:03.322939+0800 ThreadSafeDemo[9117:329328] 写文件--{number = 3, name = (null)}
2018-09-04 16:33:04.326501+0800 ThreadSafeDemo[9117:329329] 写文件--{number = 4, name = (null)}
2018-09-04 16:33:05.327306+0800 ThreadSafeDemo[9117:329330] 写文件--{number = 5, name = (null)}
2018-09-04 16:33:06.332040+0800 ThreadSafeDemo[9117:329328] 读文件--{number = 3, name = (null)}
2018-09-04 16:33:06.332040+0800 ThreadSafeDemo[9117:329330] 读文件--{number = 5, name = (null)}
2018-09-04 16:33:06.332040+0800 ThreadSafeDemo[9117:329329] 读文件--{number = 4, name = (null)}
从执行结果可以看出, 写文件的操作不能同时进行, 而读文件的操作可以同时进行.
dispatch_barrier_async方案
@interface YYFileBarrier()
@property (nonatomic ,strong) dispatch_queue_t queue;
@end
@implementation YYFileBarrier
- (instancetype)init {
if (self = [super init]) {
_queue = dispatch_queue_create("com.onealon.queue", DISPATCH_QUEUE_CONCURRENT);
}
return self;
}
- (void)readWriteTest {
dispatch_async(_queue, ^{
[self readFile];
});
dispatch_async(_queue, ^{
[self readFile];
});
dispatch_async(_queue, ^{
[self readFile];
});
dispatch_barrier_async(_queue, ^{
[self writeFile];
});
dispatch_barrier_async(_queue, ^{
[self writeFile];
});
}
- (void)readFile {
sleep(1);
NSLog(@"读文件--%@", [NSThread currentThread]);
}
- (void)writeFile {
sleep(1);
NSLog(@"写文件--%@", [NSThread currentThread]);
}
@end
执行结果:
2018-09-04 16:40:09.808536+0800 ThreadSafeDemo[9237:334097] 读文件--{number = 3, name = (null)}
2018-09-04 16:40:09.808536+0800 ThreadSafeDemo[9237:334103] 读文件--{number = 4, name = (null)}
2018-09-04 16:40:09.808536+0800 ThreadSafeDemo[9237:334104] 读文件--{number = 5, name = (null)}
2018-09-04 16:40:10.814300+0800 ThreadSafeDemo[9237:334104] 写文件--{number = 5, name = (null)}
2018-09-04 16:40:11.817018+0800 ThreadSafeDemo[9237:334104] 写文件--{number = 5, name = (null)}
后续添加:
阅读
AFNetworking
源码时发现在AFURLRequestSerialization
中设置请求头数据时也使用到了dispatch_barrier_async
多读单写操作.
- (void)setValue:(NSString *)value
forHTTPHeaderField:(NSString *)field
{
dispatch_barrier_async(self.requestHeaderModificationQueue, ^{
[self.mutableHTTPRequestHeaders setValue:value forKey:field];
});
}
- (NSString *)valueForHTTPHeaderField:(NSString *)field {
NSString __block *value;
dispatch_sync(self.requestHeaderModificationQueue, ^{
value = [self.mutableHTTPRequestHeaders valueForKey:field];
});
return value;
}