GCD

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 --- {number = 1, name = main}
    3 --- {number = 1, name = main}
    1 --- {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)