本篇文章将介绍iOS开发中的线程模块,涉及实现方式、多线程、串并行、同步异步、线程间通信、以及线程安全

iOS应用中,每一个应用都至少有一个主队列(MainQueue)和其对应的主线程(MainThread),并存在一个让应用存活的主RunLoop中。一个应用的存活与简单操作,其实一个线程就够了。但是,实际中我们开发的应用并不简单,涉及很多和复杂的业务需求。针对于大量的复杂的业务需求,那多线程的存在就至关重要了。

多线程的目的其实就是提高效率。

  • 多线程实现方案
  • 线程的多种形态
  • 多线程使用场景
  • 线程安全

1 多线程实现方案

iOS中,多线程的实现方法主要有以下四种方式:

1.1 pthread

pthread是C语言实现的,API是C语言的,它是跨平台的,由于是C语言实现,其性能较高。但是在开发时效率会低,因为其实现的线程生命周期需要开发者自己实现。

  1. // 申明/定义
  2. pthread_t thread1;
  3. // 创建,run是方法
  4. pthread_create(&thread1, NULL, run, NULL);
  5. pthread_t thread2;
  6. pthread_create(&thread2, NULL, run, NULL);
  7. // c语言函数
  8. void *run(void *param) {
  9. NSLog(@"%@",[NSThread currentThread]);
  10. return NULL;
  11. }

1.2 NSThread

NSThrad是OC语言实现的,它是对pthread进行面向对象的封装,因其多了一层封装,他的性能是低于pthread的,但是其是面向对象的API,开发效率上会优于pthread。

  1. // 创建线程---方式1
  2. NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"thread1"];
  3. thread1.name = @"thread1";
  4. // 启动线程
  5. [thread1 start];
  6. // 创建线程---方式2
  7. [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"thread2"];

1.3 GCD

CGD是C语言实现的,直接面向设备内核进行实现,充分利用设备的多核,旨在替代NSThread等线程技术,并且其生命周期自动管理,大大提高了开发者的开发效率。

  1. // 创建串行
  2. dispatch_queue_t queue = dispatch_queue_create("kirk", DISPATCH_QUEUE_SERIAL);
  3. // 创建并行队列
  4. dispatch_queue_t queue = dispatch_queue_create("kirk", DISPATCH_QUEUE_CONCURRENT);
  5. // 获取主队列
  6. dispatch_queue_t queue = dispatch_get_main_queue();
  7. // 获取全局队列,其是并行队列
  8. dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  9. // 队列的当前线程中添加同步任务,不会开辟新的线程,如果队列是当前队列,会造成现在阻塞卡死
  10. dispatch_sync(queue, ^{
  11. for (int i = 0; i<10; i++) {
  12. NSLog(@"1---%@",[NSThread currentThread]);
  13. }
  14. });
  15. // 在队列的当前线程添加异步执行任务,如果队列queue不是当前队列会开辟新的线程
  16. // 如果是当前队列,不会开启新的线程
  17. dispatch_async(queue, ^{
  18. for (int i = 0; i<10; i++) {
  19. NSLog(@"2---%@",[NSThread currentThread]);
  20. }
  21. });

1.4 NSOperation

NSOperation是OC语言实现的,基于GCD(底层是GCD)的面向对象的封装,比GCD多了一些更简单实用的功能,使用更加面向对象,其生命周期自动管理

  1. // 创建队列
  2. NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  3. // 创建任务
  4. NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run1) object:nil];
  5. NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
  6. NSLog(@"2---%@",[NSThread currentThread]);
  7. }];
  8. // 队列中添加任务
  9. [queue addOperation:op1];
  10. [queue addOperation:op2];
  11. [op2 start];

2 线程的多种形态

这个模块将介绍多线程的执行形式——同步、异步执行,以及对其进行管理的队列——并行、串行队列。

2.1 线程:

是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行或串行执行不同的任务。

2.2 队列:

其是先进先出的线性表。其只允许在后端进行插入操作,在前端进行删除操作。在多线程中,线程的管理依赖队列。每个线程队列中会有一个或多个线程处理任务。根据其执行的顺序可以分为串行队列和并行队列。

2.3 串行队列(Serial Dispatch Queue):

即队列中的任务是一个接着一个地执行,一个任务执行完毕后,再执行下一个任务。
串行队列中,即使里面的线程是异步执行的,也需要一个接一个的按顺序执行。

  1. // 创建串行队列 --- gcd
  2. dispatch_queue_t queue = dispatch_queue_create("kirk", DISPATCH_QUEUE_SERIAL);
  3. // 主队列:
  4. dispatch_queue_t queue = dispatch_get_main_queue();
  5. // 创建串行队列 ---NSOperation
  6. NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 创建队列
  7. // 设置队列最大并发量为1,队列中添加的任务会在新的子线程中执行,并且依次执行
  8. queue.maxConcurrentOperationCount = 1;

2.4 并行队列(Concurrent Dispatch Queue):

即队列中的任务是并发(同时)执行的,多个线程会同时开启执行任务。

  1. // 创建并行队列 --- gcd
  2. dispatch_queue_t queue = dispatch_queue_create("kirk", DISPATCH_QUEUE_CONCURRENT);
  3. // 获取全局队列,这个队列是并行队列
  4. dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  5. // 创建并行队列 ---NSOperation
  6. NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 创建队列
  7. queue.maxConcurrentOperationCount = 5; // 设置队列最大并发量为5

2.5 异步任务:

异步执行任务,具备开辟新线程的能力。如果在当前线程所在的队列中添加异步任务,不会开启新的线程,而非当前队列添加任务时会创建开辟新的线程。

  1. // 添加异步任务,会不会创建新的线程取决于queue是不是并行队列,只有是并行队列才会开辟新的线程
  2. dispatch_async(queue, ^{
  3. for (int i = 0; i<10; i++) {
  4. NSLog(@"1---%@",[NSThread currentThread]);
  5. }
  6. });
  7. // 添加异步任务,queue添加的任务在子线程中执行,并且多个任务是同时执行的
  8. NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  9. queue.maxConcurrentOperationCount = 5;
  10. [queue addOperationWithBlock:^{
  11. NSLog(@"1---%@",[NSThread currentThread]);
  12. }];
  13. // taget任务
  14. NSInvocationOperation *operation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOpereation1) object:nil];
  15. [queue addOperation:operation1];
  16. - (void)invocationOpereation1 {
  17. for (int i = 0; i<10; i++) {
  18. NSLog(@"2---%@",[NSThread currentThread]);
  19. }
  20. }
  21. // 打印信息是交替打印,1和2交替打印

2.6 同步任务:

这里的同步,不是指同时执行,而是在当前线程中执行,按照执行顺序依次执行。

  1. // 添加同步任务,在当前线程执行
  2. dispatch_sync(queue, ^{
  3. for (int i = 0; i<10; i++) {
  4. NSLog(@"1---%@",[NSThread currentThread]);
  5. }
  6. });
  7. // 添加异步任务,queue添加的任务是在子线程中执行,并且是串行,依次执行
  8. NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  9. queue.maxConcurrentOperationCount = 1;
  10. [queue addOperationWithBlock:^{
  11. NSLog(@"1---%@",[NSThread currentThread]);
  12. }];
  13. // taget任务
  14. NSInvocationOperation *operation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOpereation1) object:nil];
  15. [queue addOperation:operation1];
  16. - (void)invocationOpereation1 {
  17. for (int i = 0; i<10; i++) {
  18. NSLog(@"2---%@",[NSThread currentThread]);
  19. }
  20. }
  21. // 打印信息是依次打印,打印完1再2

2.7 队列组

对于队列和任务,可以将其添加到队列组中,队列组可控制其执行顺序。

  1. // 创建队列组-----gcd
  2. dispatch_group_t group = dispatch_group_create();

控制三个任务的执行顺序,任务一、二异步完成后再完成任务三

  1. // 创建队列组
  2. dispatch_group_t group = dispatch_group_create();
  3. // 创建并发队列
  4. dispatch_queue_t queue = dispatch_queue_create("my_queue", DISPATCH_QUEUE_CONCURRENT);
  5. // 添加异步任务1
  6. dispatch_group_async(group, queue, ^{
  7. for (int i = 0; i < 5; i++) {
  8. NSLog(@"任务1-%@", [NSThread currentThread]);
  9. }
  10. });
  11. // 添加异步任务2
  12. dispatch_group_async(group, queue, ^{
  13. for (int i = 0; i < 5; i++) {
  14. NSLog(@"任务2-%@", [NSThread currentThread]);
  15. }
  16. });
  17. // 等前面的任务执行完毕后,会自动执行这个任务
  18. dispatch_group_notify(group, queue, ^{
  19. for (int i = 0; i < 5; i++) {
  20. NSLog(@"任务3-%@", [NSThread currentThread]);
  21. }
  22. });

2.8 线程栅栏:barrier

在一个队列中,前面的任务执行完才执行后面的任务。

  1. dispatch_queue_t queue = dispatch_queue_create("ckck", DISPATCH_QUEUE_CONCURRENT);
  2. dispatch_async(queue, ^{
  3. for (int i = 0; i<10; i++) {
  4. NSLog(@"1---%@",[NSThread currentThread]);
  5. sleep(1);
  6. }
  7. });
  8. dispatch_async(queue, ^{
  9. for (int i = 0; i<10; i++) {
  10. NSLog(@"2---%@",[NSThread currentThread]);
  11. sleep(1);
  12. }
  13. });
  14. dispatch_async(queue, ^{
  15. for (int i = 0; i<10; i++) {
  16. NSLog(@"3---%@",[NSThread currentThread]);
  17. sleep(1);
  18. }
  19. });
  20. //在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行
  21. dispatch_barrier_async(queue, ^{
  22. NSLog(@"barrier---%@",[NSThread currentThread]);
  23. });
  24. dispatch_async(queue, ^{
  25. for (int i = 0; i<10; i++) {
  26. NSLog(@"4---%@",[NSThread currentThread]);
  27. sleep(1);
  28. }
  29. });
  30. dispatch_async(queue, ^{
  31. for (int i = 0; i<10; i++) {
  32. NSLog(@"5---%@",[NSThread currentThread]);
  33. sleep(1);
  34. }
  35. });
  36. dispatch_async(queue, ^{
  37. for (int i = 0; i<10; i++) {
  38. NSLog(@"6---%@",[NSThread currentThread]);
  39. sleep(1);
  40. }
  41. });
  42. // 123执行完(123是交替执行的),然后执行barrier,然后执行456(也是交替执行的)

2.9 其他:

只执行一次:

  1. static dispatch_once_t onceToken;
  2. dispatch_once(&onceToken, ^{
  3. NSLog(@"111111111");
  4. });

延迟执行

  1. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (ino64_t)(2 *NSEC_PER_SEC)),dispatch_get_main_queue(), ^{
  2. NSLog(@"11111");
  3. });

关于多线程相关的这篇文章就讲这么多,基本上能满足我们日常开发中对于多线程的需求。当然,关于线程安全方面,接下来将介绍。

3 线程安全&锁

线程安全,简单来说,就是多线程操作共享数据不会出现想不到的结果就是线程安全的,否则,是线程不安全的。

比如,我的钱包money数值,如果在两个地方同时存取,之前我的money是500,然后a处要存入100,b处要取出50,且这两个几乎同时操作,a处看到的初始值是500,那么存入100后是600,存入是600,但是b在a存入前拿到了初始值时500,这时候取出50,那么取出后的值时450。这就出现了线程不安全。

为了保证线程安全,锁就出现了。锁的原理是,在其进行一次操作值的时候将其锁住,只能本次操作,将其他操作锁住外面,等此次操作结束后,解锁,依次处理下一次操作。

iOS中保护线程安全的方案锁有很多种,比如OSSpinLock、os_unfair_lock、pthread_mutex、dispatch_semaphore、NSLock、NSRecursiveLock、NSCondition、NSConditionLock、@synchronized等,本文将阐述几种常用的,其他的用法都差不多就不再具体展开。

3.1 自旋锁

自旋锁,其实现原理是一个死循环。当a线程获得锁以后,b线程想要获取锁就需要等待a线程释放锁。在没有获得锁的期间,b线程会一直处于忙等的状态。因此自旋锁的劣势是一直占用着CPU资源,消耗性能。

3.1.1 OSSpinLock

目前已经不再安全,可能会出现优先级反转问题(p如果等待锁的线程优先级较高,它会一直占用着CPU资源,优先级低的线程就无法释放锁)

需要导入头文件#import

  1. // 初始化线程锁
  2. self.moneyLock = OS_SPINLOCK_INIT;
  3. // 取钱
  4. - (void)drawMoney
  5. {
  6. // 加锁
  7. OSSpinLockLock(&_moneyLock);
  8. //drawMoney...
  9. // 解锁
  10. OSSpinLockUnlock(&_moneyLock);
  11. }
  12. // 存钱
  13. - (void)saveMoney
  14. {
  15. // 加锁
  16. OSSpinLockLock(&_moneyLock);
  17. // saveMoney.....
  18. // 解锁
  19. OSSpinLockUnlock(&_moneyLock);
  20. }

3.1.2 os_unfair_lock

用于取代不安全的OSSpinLock ,从iOS10开始才支持

从底层调用看,等待os_unfair_lock锁的线程会处于休眠状态,并非忙等

需要导入头文件#import

  1. // 初始化锁
  2. self.moneyLock = OS_UNFAIR_LOCK_INIT;
  3. // 存钱
  4. - (void)saveMoney
  5. {
  6. // 加锁
  7. os_unfair_lock_lock(&_moneyLock);
  8. // saveMoney.....
  9. // 解锁
  10. os_unfair_lock_unlock(&_moneyLock);
  11. }
  12. // 取钱
  13. - (void)drawMoney
  14. {
  15. // 加锁
  16. os_unfair_lock_lock(&_moneyLock);
  17. //drawMoney...
  18. // 解锁
  19. os_unfair_lock_unlock(&_moneyLock);
  20. }

3.2 互斥锁

3.2.1 pthread_mutex

叫做”互斥锁”,等待锁的线程会处于休眠状态。

其有五个函数进行操作:

1> pthreadmutex_init(pthread_mutex_t mutex,const pthread_mutexattr_t _attr)。初始化锁变量mutex。attr为锁属性,NULL值为默认属性。

2> pthread_mutex_lock(pthread_mutex_t *mutex);加锁

3> pthread_mutex_tylock(pthread_mutex_t *mutex);加锁,但是与2不一样的是当锁已经在使用的时候,返回为EBUSY,而不是挂起等待。

4> pthread_mutex_unlock(pthread_mutex_t *mutex);释放锁

5> pthread_mutex_destroy(pthread_mutex_t *mutex);使用完后释放

需要导入头文件#import

  1. @property (assign, nonatomic) pthread_mutex_t moneyMutex;
  2. // 初始化锁:1、初始化锁的属性,2、初始化锁
  3. // 初始化属性
  4. pthread_mutexattr_t attr;
  5. pthread_mutexattr_init(&attr);
  6. pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
  7. // 初始化锁
  8. pthread_mutex_init(mutex, NULL);
  9. // 销毁属性
  10. pthread_mutexattr_destroy(&attr);
  11. // 存钱
  12. - (void)__saveMoney
  13. {
  14. // 加锁
  15. pthread_mutex_lock(&_moneyMutex);
  16. // saveMoney.....
  17. // 解锁
  18. pthread_mutex_unlock(&_moneyMutex);
  19. }
  20. // 取钱
  21. - (void)__drawMoney
  22. {
  23. // 加锁
  24. pthread_mutex_lock(&_moneyMutex);
  25. //drawMoney...
  26. // 解锁
  27. pthread_mutex_unlock(&_moneyMutex);
  28. }
  29. // 销毁锁
  30. - (void)dealloc
  31. {
  32. pthread_mutex_destroy(&_moneyMutex);
  33. }

3.2.2 NSLock

NSLock是对mutex普通锁的封装

  1. self.moneyLock = [[NSLock alloc] init];
  2. - (void)__saveMoney
  3. {
  4. [self.moneyLock lock];
  5. // save
  6. [self.moneyLock unlock];
  7. }
  8. - (void)__drawMoney
  9. {
  10. [self.moneyLock lock];
  11. // draw
  12. [self.moneyLock unlock];
  13. }

3.3 递归锁

递归锁:允许同一个线程对一把锁进行重复加锁,递归锁的实现就是将互斥锁的属性进行设置

  1. // 初始化锁:1、初始化锁的属性,2、初始化锁
  2. // 初始化属性
  3. pthread_mutexattr_t attr;
  4. pthread_mutexattr_init(&attr);
  5. pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); // 递归锁标识
  6. // 初始化锁
  7. pthread_mutex_init(mutex, NULL);
  8. // 销毁属性
  9. pthread_mutexattr_destroy(&attr);
  10. - (void)test
  11. {
  12. // 加锁
  13. pthread_mutex_lock(&_mutex);
  14. NSLog(@"%s", __func__);
  15. static int count = 0;
  16. if (count < 10) {
  17. count++;
  18. [self otherTest];
  19. }
  20. // 解锁
  21. pthread_mutex_unlock(&_mutex);
  22. }

3.3.2 @synchronized

是对mutex递归锁的封装,@synchronized(obj)内部会生成obj对应的递归锁,然后进行加锁、解锁操作

  1. @synchronized (objc) {
  2. // 对objc的操作
  3. }

3.3.3 NSRecursiveLock

对mutex递归锁的封装,API跟NSLock基本一致

3.4 条件锁

可以添加条件

  1. @property (assign, nonatomic) pthread_mutex_t mutex; // 锁
  2. @property (assign, nonatomic) pthread_cond_t cond; // 条件
  3. @property (strong, nonatomic) NSMutableArray *data;
  4. // 初始化
  5. // 初始化属性
  6. pthread_mutexattr_t attr;
  7. pthread_mutexattr_init(&attr);
  8. pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
  9. // 初始化锁
  10. pthread_mutex_init(&_mutex, &attr);
  11. // 销毁属性
  12. pthread_mutexattr_destroy(&attr);
  13. // 初始化条件
  14. pthread_cond_init(&_cond, NULL);
  15. self.data = [NSMutableArray array];
  16. // 生产者-消费者模式
  17. // 线程1
  18. // 删除数组中的元素
  19. - (void)__remove
  20. {
  21. pthread_mutex_lock(&_mutex);
  22. NSLog(@"__remove - begin");
  23. if (self.data.count == 0) {
  24. // 等待
  25. pthread_cond_wait(&_cond, &_mutex);
  26. }
  27. [self.data removeLastObject];
  28. NSLog(@"删除了元素");
  29. pthread_mutex_unlock(&_mutex);
  30. }
  31. // 线程2
  32. // 往数组中添加元素
  33. - (void)__add
  34. {
  35. pthread_mutex_lock(&_mutex);
  36. sleep(1);
  37. [self.data addObject:@"Test"];
  38. NSLog(@"添加了元素");
  39. // 信号
  40. pthread_cond_signal(&_cond);
  41. // 广播
  42. // pthread_cond_broadcast(&_cond);
  43. pthread_mutex_unlock(&_mutex);
  44. }
  45. // 最后销毁锁和条件
  46. - (void)dealloc
  47. {
  48. pthread_mutex_destroy(&_mutex);
  49. pthread_cond_destroy(&_cond);
  50. }

3.4.1 NSCondition

NSCondition是对mutex和cond的封装

3.4.2 NSConditionLock

是对NSCondition的进一步封装,可以设置具体的条件值

3.5 信号量

3.5.1 dispatch_semaphore

信号量的初始值,可以用来控制线程并发访问的最大数量

信号量的初始值为1,代表同时只允许1条线程访问资源,保证线程同步

  1. @property (strong, nonatomic) dispatch_semaphore_t semaphore;
  2. @property (strong, nonatomic) dispatch_semaphore_t ticketSemaphore;
  3. @property (strong, nonatomic) dispatch_semaphore_t moneySemaphore;
  4. - (instancetype)init
  5. {
  6. if (self = [super init]) {
  7. self.semaphore = dispatch_semaphore_create(5);
  8. self.ticketSemaphore = dispatch_semaphore_create(1);
  9. self.moneySemaphore = dispatch_semaphore_create(1);
  10. }
  11. return self;
  12. }
  13. - (void)__drawMoney
  14. {
  15. dispatch_semaphore_wait(self.moneySemaphore, DISPATCH_TIME_FOREVER);
  16. [super __drawMoney];
  17. dispatch_semaphore_signal(self.moneySemaphore);
  18. }
  19. - (void)__saveMoney
  20. {
  21. dispatch_semaphore_wait(self.moneySemaphore, DISPATCH_TIME_FOREVER);
  22. [super __saveMoney];
  23. dispatch_semaphore_signal(self.moneySemaphore);
  24. }
  25. - (void)__saleTicket
  26. {
  27. dispatch_semaphore_wait(self.ticketSemaphore, DISPATCH_TIME_FOREVER);
  28. [super __saleTicket];
  29. dispatch_semaphore_signal(self.ticketSemaphore);
  30. }
  31. - (void)otherTest
  32. {
  33. for (int i = 0; i < 20; i++) {
  34. [[[NSThread alloc] initWithTarget:self selector:@selector(test) object:nil] start];
  35. }
  36. }
  37. // 线程10、7、6、9、8
  38. - (void)test
  39. {
  40. // 如果信号量的值 > 0,就让信号量的值减1,然后继续往下执行代码
  41. // 如果信号量的值 <= 0,就会休眠等待,直到信号量的值变成>0,就让信号量的值减1,然后继续往下执行代码
  42. dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
  43. sleep(2);
  44. NSLog(@"test - %@", [NSThread currentThread]);
  45. // 让信号量的值+1
  46. dispatch_semaphore_signal(self.semaphore);
  47. }

3.6 自旋锁、互斥锁比较

使用自旋锁:

1> 预计线程等待锁的时间很短

2> 加锁的代码(临界区)经常被调用,但竞争情况很少发生

3> CPU资源不紧张

4> 多核处理器

使用互斥锁:

1> 预计线程等待锁的时间较长

2> 预计线程等待锁的时间较长

3> 临界区有IO操作

4>临界区代码复杂或者循环量大,临界区竞争非常激烈

3.7 atomic

用于保证属性setter、getter的原子性操作,相当于在getter和setter内部加了线程同步的锁

可以参考源码objc4的objc-accessors.mm

它并不能保证使用属性的过程是线程安全的

4 线程读写安全方案

线程读写安全的出现:多读单写,经常用于文件等数据的读写操作,iOS中的实现方案有

同一时间,只能有1个线程进行写的操作

同一时间,允许有多个线程进行读的操作

同一时间,不允许既有写的操作,又有读的操作

其实现的方案有:
pthread_rwlock:读写锁
dispatch_barrier_async:异步栅栏调用

4.1 pthread_rwlock

其读数据锁和写数据锁是两个不同的函数,进行区分操作

  1. // 初始化锁
  2. pthread_rwlock_init(&_lock, NULL);
  3. // 读加锁
  4. pthread_rwlock_rdlock(&_lock);
  5. // 读尝试加锁
  6. pthread_rwlock_tryrdlock(&_lock);
  7. // 写加锁
  8. pthread_rwlock_wrlock(&_lock);
  9. // 写尝试加锁
  10. pthread_rwlock_trywrlock(&_lock);
  11. // 解锁
  12. pthread_rwlock_unlock(&_lock);
  13. // 销毁锁
  14. pthread_rwlock_destroy(&_lock);

4.2 dispatch_barrier_async

这个函数传入的并发队列必须是自己通过dispatch_queue_cretate创建的

如果传入的是一个串行或是一个全局的并发队列,那这个函数便等同于dispatch_async函数的效果

  1. // 初始化队列
  2. self.queue = dispatch_queue_create("rw_queue", DISPATCH_QUEUE_CONCURRENT);
  3. // 使用
  4. for (int i = 0; i < 10; i++) {
  5. dispatch_async(self.queue, ^{
  6. [self read];
  7. });
  8. dispatch_async(self.queue, ^{
  9. [self read];
  10. });
  11. dispatch_async(self.queue, ^{
  12. [self read];
  13. });
  14. // 前面三个任务同步执行,执行完后再执行这个,这个执行完再到下一步
  15. dispatch_barrier_async(self.queue, ^{
  16. [self write];
  17. });
  18. }
  19. - (void)read {
  20. sleep(1);
  21. NSLog(@"read");
  22. }
  23. - (void)write {
  24. sleep(1);
  25. NSLog(@"write");
  26. }

以上。

不对之处,可评论探讨。