GCD

作者: 和风细羽 | 来源:发表于2019-12-03 21:10 被阅读0次

    GCD

    队列与线程的关系

    • 主队列和主线程

    • 『ios』主线程 和 主队列的关系,绝对安全的UI操作,主线程中一定是主队列?

      - (void)testInMainThread
      {
          // 异步提交任务到主队列
          dispatch_async(dispatch_get_main_queue(), ^{
              NSLog(@"1 --- %@", [NSThread currentThread]); 
              self.label.backgroundColor = [UIColor orangeColor];  // 正常
          });
      
          // 同步提交任务到自定义并发队列
          dispatch_sync(dispatch_queue_create("queue1", DISPATCH_QUEUE_CONCURRENT), ^{
              NSLog(@"2 --- %@", [NSThread currentThread]);
              self.label.backgroundColor = [UIColor greenColor];  // 正常
          });
      
          // 同步提交任务到自定义串行队列
          dispatch_sync(dispatch_queue_create("queue2", DISPATCH_QUEUE_SERIAL), ^{
              NSLog(@"3 --- %@", [NSThread currentThread]); 
              self.label.backgroundColor = [UIColor whiteColor];  // 正常
          });
      }
      
      2 --- <NSThread: 0x6000039a1400>{number = 1, name = main}
      3 --- <NSThread: 0x6000039a1400>{number = 1, name = main}
      1 --- <NSThread: 0x6000039a1400>{number = 1, name = main}
      
    1. 队列不是线程。队列用来组织任务,线程是执行队列中的任务。
    2. 主队列是一个特殊的串行队列,异步提交任务到主队列不会开辟新线程。
    3. 一个线程可以执行多个队列中的任务。
    4. 只要在主线程,主队列、自定义的串行/并发队列任务都能够刷新 UI。
    5. 主队列不一定在主线程执行,比如:人为调用 dispatch_main()。

    死锁

    用 dispatch_sync 添加任务到它自己所在的串行队列中就会造成死锁。

    死锁的三个条件:

    1. dispatch_sync(同步)添加任务
    2. 串行队列
    3. 添加的任务和 dispatch_sync 在同一个队列
    - (void)testInMainThread
    {
        // 情形 ①、dispatch_sync 自身在主队列
        dispatch_sync(dispatch_get_main_queue(), ^{        
    
        });
    
        dispatch_queue_t queue = dispatch_queue_create("CONCURRENT", DISPATCH_QUEUE_SERIAL);
        dispatch_async(queue, ^{
            // 情形 ②、dispatch_sync 自身在 queue 队列
            dispatch_sync(queue, ^{
                NSLog(@"222");
            });
        });
    }
    

    解决方案就是让死锁的三个条件中任意一个不满足即可。

    读写安全方案

    • 同一时间,只允许一个线程执行写入操作
    • 同一时间,许多个线程都执行读取操作
    • 同一时间,不能既有写入操作,也有读取操作

    方案:

    1. dispatch_semaphore 信号量,缺陷是不能实现允许多个线程读取操作
    2. dispatch_barrier_async 栅栏,注意读写任务队列必须是自己创建的并发队列
    3. pthread_rwlock 读写锁

    多线程:GCD

    数据竞争

    多个线程并发执行,同一时间访问同一块数据(如同一个变量、对象、文件等),就有可能出现数据竞争,从而导致数据错乱。

    线程同步

    方案:

    1. 加锁。多个线程使用同一把锁,对访问数据的关键代码进行加锁;
      • OSSpinLock 自旋锁
      • os_unfair_lock 互斥锁
      • pthread_mutex 互斥锁
      • NSLock 互斥锁
      • NSRecursiveLock 递归锁
      • @synchronized
    2. 设置线程的最大并发数为 1
    3. 把多个线程放入串行队列

    其中方案 2 和 3 差不多。

    意一ineyee - 多线程:数据竞争问题与线程同步方案

    相关文章

      网友评论

        本文标题:GCD

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