iOS多线程同步方案

作者: OneAlon | 来源:发表于2018-09-04 16:52 被阅读37次

    上篇文章中已经讨论了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] 写文件--<NSThread: 0x604000275240>{number = 3, name = (null)}
    2018-09-04 16:33:04.326501+0800 ThreadSafeDemo[9117:329329] 写文件--<NSThread: 0x6040002744c0>{number = 4, name = (null)}
    2018-09-04 16:33:05.327306+0800 ThreadSafeDemo[9117:329330] 写文件--<NSThread: 0x604000276d40>{number = 5, name = (null)}
    2018-09-04 16:33:06.332040+0800 ThreadSafeDemo[9117:329328] 读文件--<NSThread: 0x604000275240>{number = 3, name = (null)}
    2018-09-04 16:33:06.332040+0800 ThreadSafeDemo[9117:329330] 读文件--<NSThread: 0x604000276d40>{number = 5, name = (null)}
    2018-09-04 16:33:06.332040+0800 ThreadSafeDemo[9117:329329] 读文件--<NSThread: 0x6040002744c0>{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] 读文件--<NSThread: 0x600000067ec0>{number = 3, name = (null)}
    2018-09-04 16:40:09.808536+0800 ThreadSafeDemo[9237:334103] 读文件--<NSThread: 0x60400027e080>{number = 4, name = (null)}
    2018-09-04 16:40:09.808536+0800 ThreadSafeDemo[9237:334104] 读文件--<NSThread: 0x604000460680>{number = 5, name = (null)}
    2018-09-04 16:40:10.814300+0800 ThreadSafeDemo[9237:334104] 写文件--<NSThread: 0x604000460680>{number = 5, name = (null)}
    2018-09-04 16:40:11.817018+0800 ThreadSafeDemo[9237:334104] 写文件--<NSThread: 0x604000460680>{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多线程同步方案

        本文链接:https://www.haomeiwen.com/subject/xsbgwftx.html