美文网首页
多线程读写安全的解决办法

多线程读写安全的解决办法

作者: Sweet丶 | 来源:发表于2020-10-25 15:46 被阅读0次

对于同一个资源,如果多个线程同时执行"写"操作,那么就容易造成资源的"写"操作出错;如果在写入的过程中进行"读"的操作,那么就可能读取了"写"操作执行到一半的东西,这两者都不是我们想要的,所以就有了读写安全的方案:

  1. 在没有“写”操作执行中时,允许多个线程同时”读”。
  2. 在有“读”操作时,“写”操作可以执行,但这个“写”执行时,不允许再有“读”和“写”操作同时执行,必须等这个“写”执行完之后才可以。

iOS 中实现上述思路的方案有两个:

  1. pthread_rwlock: 系统库#import <pthread/pthread.h>里面的函数, 有对应的“读”锁和“写”锁。
  2. dispatch_barrier_async:GCD的栅栏函数,这个函数能让此任务添加到并发队列后,先执行完之前添加的任务,再执行此任务,等这个任务执行之后最后再执行后面添加到对应queue的任务。所以读跟写的操作都放在同一个队列中,其中“写”任务用dispatch_barrier_async来添加就能实现读写安全。

具体使用:

一、dispatch_barrier_async
+ (void)barrierTest{
    dispatch_queue_t queue = dispatch_queue_create("ReadWriteLock_con", DISPATCH_QUEUE_CONCURRENT);
    
    for (int i = 0; i<10; i++) {// 将10个读取任务添加到queue中
        dispatch_async(queue, ^{
            NSLog(@"读任务执行------“写”前");
            sleep(0.5);
        });
    }
    
    for (int i = 0; i < 3; i++) {// 将3个写任务添加到queue中
        dispatch_barrier_async(queue, ^{
            NSLog(@"写任务执行------“写”");
            sleep(3);
        });
        
        dispatch_async(queue, ^{
            NSLog(@"读任务执行------“写”后");
            sleep(0.5);
        });
        dispatch_async(queue, ^{
            NSLog(@"读任务执行------“写”后");
            sleep(0.5);
        });
    }
}

打印:

2020-10-25 14:05:10.397 KVO[10978:1023342] 读任务执行------“写”前
2020-10-25 14:05:10.397 KVO[10978:1023354] 读任务执行------“写”前
2020-10-25 14:05:10.397 KVO[10978:1023355] 读任务执行------“写”前
2020-10-25 14:05:10.397 KVO[10978:1023361] 读任务执行------“写”前
2020-10-25 14:05:10.397 KVO[10978:1023363] 读任务执行------“写”前
2020-10-25 14:05:10.397 KVO[10978:1023350] 读任务执行------“写”前
2020-10-25 14:05:10.397 KVO[10978:1023362] 读任务执行------“写”前
2020-10-25 14:05:10.397 KVO[10978:1023359] 读任务执行------“写”前
2020-10-25 14:05:10.397 KVO[10978:1023360] 读任务执行------“写”前
2020-10-25 14:05:10.397 KVO[10978:1023364] 读任务执行------“写”前
2020-10-25 14:05:10.398 KVO[10978:1023364] 写任务执行------“写”
2020-10-25 14:05:13.402 KVO[10978:1023364] 读任务执行------“写”后
2020-10-25 14:05:13.402 KVO[10978:1023360] 读任务执行------“写”后
2020-10-25 14:05:13.403 KVO[10978:1023360] 写任务执行------“写”
2020-10-25 14:05:16.407 KVO[10978:1023360] 读任务执行------“写”后
2020-10-25 14:05:16.407 KVO[10978:1023364] 读任务执行------“写”后
2020-10-25 14:05:16.408 KVO[10978:1023364] 写任务执行------“写”
2020-10-25 14:05:19.412 KVO[10978:1023364] 读任务执行------“写”后
2020-10-25 14:05:19.412 KVO[10978:1023360] 读任务执行------“写”后

关键点:

  1. 传入的queue需要是自己创建的并发队列,不能是串行队列DISPATCH_QUEUE_SERIAL或者是全局的并发队列dispatch_get_global_queue.
  2. 从打印中看出dispatch_barrier_async添加的“写”任务需要等前面的10个“读”任务都执行完才开始,“写”任务后面的2个“读”任务要等前面的“写”执行完才开始。
  3. 缺点:读写任务都要放在同一个queue否则也是没有用的。
二、pthread_rwlock
- (void)testPthreadrwlock{
    pthread_rwlock_init(&(_rwlock), NULL);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    for (int i = 0; i<10; i++) {// 将5个读取任务添加到queue中
        dispatch_async(queue, ^{
            [self read];
        });
    }
    
    for (int i = 0; i < 3; i++) {// 将3个写任务添加到queue中
        dispatch_async(queue, ^{
            [self write];
        });
        
        dispatch_async(queue, ^{
            [self read];
        });
        dispatch_async(queue, ^{
            [self read];
        });
    }
}


- (void)read{
    pthread_rwlock_rdlock(&_rwlock);
    NSLog(@"读操作");
    sleep(0.5);
    pthread_rwlock_unlock(&_rwlock);
}

- (void)write{
    pthread_rwlock_wrlock(&_rwlock);
    NSLog(@"写操作");
    sleep(3);
    pthread_rwlock_unlock(&_rwlock);
}

- (void)dealloc{
    pthread_rwlock_destroy(&_rwlock);
}

打印结果跟dispatch_barrier_async是一样的
关键点:

  1. 这是一个跨平台的方案。
    使用读写锁pthread_rwlock_t

相关文章

  • 多线程读写安全的解决办法

    对于同一个资源,如果多个线程同时执行"写"操作,那么就容易造成资源的"写"操作出错;如果在写入的过程中进行"读"的...

  • 多线程-读写安全

    多线程31-读写安全01-简介 文件操作(IO操作)读取文件往文件中写入内容不能允许读取和写入同时进行我们之前做的...

  • 多线程-读写安全

  • 多线程读写安全

    多读单写 要想实现多线程的读写安全,必须满足“读读”并发,“读写”、“写写”互斥。即: 同一时间,只能有1个线程进...

  • go sync包的读写锁RWMutex的使用

    sync包的读写锁RWMutex的使用(sync.RWMutex) 我们使用“读写”锁的场景主要是在多线程的安全操...

  • 课堂模拟面试试题

    1、列举一下 Cocoa/Cocoa Touch 中常见的几种多线程方案的实现,并谈谈多线程安全的几种解决办法以及...

  • atomic 和 nonatomic 的区别

    atomic 提供多线程安全,防止读写未完成的时候被另外一个线程读写,造成数据错误nontomic 在自己管理内存...

  • 多线程 之 多线程的读写安全

    1、前言 在前面我们已经讲过了iOS中的线程同步技术,主要通过加锁实现。对于读写操作,一般都比较耗时耗性能,为了保...

  • JAVA面试汇总(二)多线程(六)

    JAVA多线程内容比较多,今天写完了第六篇,后边还有七(肯定最后一篇了)。 如何保证多线程读写文件的安全?(1)读...

  • JAVA

    1.4 Java的 内存模型 是否线程安全线程安全与cpu资源的抢夺 多线程在读写共享变量时引发的问题 线程的原子...

网友评论

      本文标题:多线程读写安全的解决办法

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