iOS多线程同步方案

在上篇文章中已经讨论了iOS中多线程方案, 本文章主要记录多线程的同步方案、文件的多读单写操作.

先附上demo地址

当多个线程同时访问同一块资源时, 容易引发数据错乱和数据安全问题, 为了解决这个问题, 引入锁的概念.

自旋锁和互斥锁
自旋锁: 如果资源被占用, 调用者会一直循环.
互斥锁: 如果资源被占用, 资源申请者就会进入休眠状态.

一. 多线程中的锁

iOS中的锁有OSSpinLock os_unfair_lock pthread_mutex dispatch_semaphore NSLock NSRecursiveLock NSCondition NSConditionLock @synchronized等, 本片文章会对上诉锁做简单的应用以及讲解.

demo中已经对锁做了笔记.

二. 文件的多读单写

同一时间, 只能允许一个线程对文件进行写操作.
同一时间, 允许多个线程对文件进行读操作.

文件的多读单写方案有pthread_rwlock_tdispatch_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;
}

你可能感兴趣的:(iOS多线程同步方案)