多线程相关

211 阅读4分钟

部分相关概念

  • 进程

一个正在执行的程序实例。作为线程的容器,是资源管理的单位。

每个进程都拥有独立且受保护的内存空间,用来存放程序正文和数据以及其打开的文件、子进程、即将发生的报警、信号处理程序、账号信息等。

iOS 中的后台只可以存在短暂的一段时间就会被挂起,在这种状态下进程将不会得到 CPU 时间片,当收到内存警告时,系统会将处于此状态的进程从内存中移除。

  • 线程

执行进程中的所有任务。是 CPU 调度的基本单位。

线程只拥有程序计数器、寄存器、堆栈等少量资源,但与其他线程共享该进程的整个内存空间。

  • 任务

表示的是一系列需要完成的工作。如 GCD 里的 BlockperformSelector 中的 selector

  • 队列

调度队列是一个对象。任务先进先出,不管是串行队列还是并发队列。

  • 队列与线程

将任务加到队列中去执行,队列会根据同步或者异步添加,以及系统负载去控制线程并发数,然后调度线程去执行追加在队列上的任务。

  • 并行 parallelism

在物理上真正的同时执行。

  • 并发 concurrent

在逻辑上的同时执行,通过时间片轮转等调度算法实现的多任务同时执行。当在多核 CPU 实现并发时,多任务才是真正物理上的同时执行。

  • 串行

按顺序执行任务,同一时间只执行一个任务。

  • 串行与并行

有 a、b、c 三个任务,单个 CPU 处理分贝需要 1s、2s、3s。

同样用三个 CPU 进行处理a、b、c。

串行处理,需要6s。在各自的线程中完成,不会减少总的执行时间,反而会因为线程上下文的切换增加处理时间。

并行处理,只需要3s。

  • 同步

发出一个调用后,得到结果才返回。

  • 同步

发出一个调用后,不等得到结果就直接返回。

  • 同步和异步

区别在于会不会阻塞当前线程,和任务的串行或并行没有关系。

有 a、b、c 三个任务,单个 CPU 处理分贝需要 3s、2s、1s。

同样用三个 CPU 进行处理a、b、c,若a是耗时计算相关的任务,b、c是 UI 相关的任务。

同步处理,需要3s去处理完a,然后再处理b、c的;

异步处理,处理a,调用后就马上接着处理b、c,不会等待a的处理完。

同步 异步
主队列 在主线程中执行 在主线程中执行
串行队列 在当前线程中执行 新建线程执行
并发队列 在当前线程中执行 新建线程执行

GCD 死锁相关

    dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
  1. 主队列中同步添加任务 ❎
    //->
    //同步添加任务到主队列尾部 阻塞当前线程
    //添加的任务要完成需要等待前面的任务完成
    //前面的任务需要等待添加的任务完成后没有阻塞才能继续执行完成
    //互相等待 死锁

    dispatch_sync(mainQueue, ^{
        NSLog(@"1"); // 任务1
    });
  1. 串行队列中同步添加任务 ❎
    //任务1
    
    dispatch_sync(serialQueue, ^{
        NSLog(@"1"); // 任务1
    });
    
    //任务1 ->
    //同步添加任务a到串行队列(位置1的整个 block )
    //执行任务1
    //同步添加任务b到串行队列尾部(位置2的整个 block )
    //a 的完成意味着 b 的完成
    //b 在队列尾部,b 在 a 完成后才执行
    //互相等待 死锁
    
    dispatch_sync(serialQueue, ^{
        //1
        NSLog(@"1"); // 任务1
        dispatch_sync(serialQueue, ^{
            //2
            NSLog(@"2"); // 任务2
        });
    });
    
    dispatch_async(serialQueue, ^{
        //1
        NSLog(@"1"); // 任务1
        dispatch_sync(serialQueue, ^{
            //2
            NSLog(@"2"); // 任务2
        });
        NSLog(@"3"); // 任务3
    });

  1. 并发队列中同步添加任务 ✅
    //任务1 -> 任务2 -> 任务3
    
    dispatch_async(globalQueue, ^{
        NSLog(@"1"); // 任务1
        dispatch_sync(globalQueue, ^{
            NSLog(@"2"); // 任务2
        });
        NSLog(@"3"); // 任务3
    });
  1. dispatch_apply 串行队列 ❎
    //1--0 ->
    //dispatch_apply 会等待其所有的循环运行完成后再执行后面的任务
    //同步添加任务a到串行队列(位置1的整个 block ),添加次数等同于 dispatch_apply 循环次数
    //执行任务1
    //同步添加任务b到串行队列尾部(位置2的整个 block )
    //互相等待 死锁

    dispatch_apply(2, serialQueue, ^(size_t i) {
        //1
        NSLog(@"1--%zu", i); // 任务1
        dispatch_apply(2, serialQueue, ^(size_t i) {
            //2
            NSLog(@"2--%zu", i); // 任务2
        });
    });
    NSLog(@"3"); // 任务3