• iOS 多线程


    经常听到这样的问题 "你在处理多线程的时候 遇到过什么问题 或者说 你使用过多线程吗 如何操作的"

    具体 我也没听过 别人是怎么回答的,我也没太想好怎样回答才算全面,今天利用工作空余时间好好系统学一下,从以下几个角度学习

    1 理论

    2 举例子运用

    3 实际开发注意要点

    一 理论

      1 线程和进程

          a 一般运行一个程序就是一个进程. 一个程序至少有一个进程,一个进程至少有一个线程

          b 线程,是进程的一部分,一个没有线程的进程可以被看作是单线程的 (相对进程而言,线程是一个更加接近于执行体的概念)

          c 进程可以创建线程 也可以创建进程 

          d 线程由进程管理,  线程之间  线程和父进程之间(创建线程的进程)共享内存变量 (需要策略实现)

          e 进程之间一般不可以直接共享内存变量,需要一些进程间的控制共享内存变量

      2 iOS 多线程编程技术(这里主讲GCD)

          NSThread  NSOperation  GCD

         (1) NSThread 

           优点: 使用起来比 其他两个更轻量级

           缺点:需要自己管理线程的生命周期,线程同步. 线程同步的加锁会又一定的系统开销

         (2)NSOperation 

           优点:无需关心线程管理,数据同步.关键是操作执行操作.

                  相关类:抽象类 NSInvocationOperation 和 NSBlockOperation

                  创建NSOperation子类对象,把对象添加到NSOperationqueue队列里执行

         (3)GCD (grand central dispatch)

            iOS4后开始使用,是代替以上两种多线程方法的强大技术,GCD中FIFO队列称为 dispatch queue

           dispatch queue :

           a  串行队列: serial 队列  队里任务 是一个一个地执行

           dispatch_queue_t  queue = dispatch_queue_create("com.xxx.serialQueue",DISPATCH_QUEUE_SERIAL);// 自己创建一个串行队列

           b  并行队列:concurrent 队列 通常任务会并发的执行     

           dispatch_queue_t  queue  =  dispatch_queue_create("com.xxx.concurrentQueue",DISPATCH_QUEUE_CONCURRENT);// 自己创建一个并行队列

          c 全局队列 : 系统级别的,直接拿来用,是一种并发队列

           dispatch_queue_t  queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);

          d 主队列 :一个应用程序对应唯一一个主队列,也是系统级别,直接拿来用,多线程开发使用主队列更新UI. 是一种串行队列

           dispatch_queue_t  queue = dispatch_get_main_queue();

     二 举例运用

      dispatch queue

    #define global_queue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
    #define main_queue dispatch_get_main_queue()

     (1)dispatch_async

         耗时懂得操作,数据处理,IO读取数据库什么的 在另一个线程中处理,然后通知主线程更新UI

         常用方法:

    dispatch_async(global_queue, ^{
        //耗时间性能的处理放在这
        dispatch_sync(main_queue, ^{
            //主线程更新UI
        });
    });

     (2)dispatch_group_async

       可以实现监听一组任务是否完成, 完成后得到通知再执行其他操作

       常用方法举例:下载 5张图片(或者说有五个独立数据请求),下载完了更新UI (都请求完成后执行其他操作)

    - (void)fun
    {
        // 创建一个组
        dispatch_group_t group = dispatch_group_create();
        
        dispatch_group_async(group, global_queue, ^{
            //开启一个任务1
        });
        
        dispatch_group_async(group, global_queue, ^{
            // 开启一个任务2
        });
       //开启一个任务3
       //开启一个任务4
       //开启一个任务5
    dispatch_group_notify(group, main_queue, ^{
    // 等group中的所有任务都执行完毕, 再回到主线程执行其他操作
        });
    }

     (3)dispathch_barrier_async(栅栏函数)

    void dispatch_barrier_async ( dispatch_queue_t queue, dispatch_block_t block );

    参数 queue: 将barrier添加到那个队列
    block: barrier block 代码块

        "在它前面的的任务执行后它才执行,在它后面的任务需要等它执行完成后才能执行".

        使用情况是和并行队列一起使用,"同dispatch_queue_create函数生成的concurrent Dispatch Queue队列一起使用", 这个queue 一定是 自己创建的 并发队列,如果是 使用全局并发队列或者是一个串行队列,那么这个函数等同于dispatch_async函数.

     使用举例:

    - (void)barrier
    {
        dispatch_queue_t queue = dispatch_queue_create("myConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);//这个queue 一定是 自己创建的 并发队列,如果是 使用全局并发队列或者是一个串行队列,那么这个函数等同于dispatch_async函数.
        
        dispatch_async(queue, ^{
            NSLog(@"任务1");
        });
        dispatch_async(queue, ^{
            NSLog(@"任务2");
        });
        
        dispatch_barrier_async(queue, ^{
            NSLog(@"barrier");
        });
        
        dispatch_async(queue, ^{
            NSLog(@"任务3");
        });
        dispatch_async(queue, ^{
            NSLog(@"任务4");
        });
    }

    打印结果

    任务1

    任务2 (1 和 2 并发 顺序不定)

    barrier

    任务3

    任务4 (3 和 4 并发 顺序不定)

      (4)dispatch_apply

       执行N次的某一个代码片段 

    
    dispatch_apply(5, global_queue, ^(size_t index){
         //此处任务执行5次
    });

    三 实际开发注意要点

         重点是关注多线程死锁问题,和正确选择多线程策略

         关于死锁,主要参考大学操作系统课程标配讲解:

         死锁原因

                 (1)资源竞争 资源分配不当

                 (2)系统资源不足

                 (3)进程运行推进顺序不合适

         死锁条件:

               (1)互斥:进程在某一时间内独占资源

               (2)请求与保持:进程已经拥有当前资源,但是又申请新资源

               (3)不可剥夺: 进程的资源没使用完 就不可以强行从资源占有者处争夺资源

               (4)循环等待 : 出现闭环

         死锁预防:(破坏上述四个必要条件的一个或者几个)

              (1)破坏上述四个必要条件的一个或者几个 来防止死锁产生

              (2)鸵鸟算法,发生错误概率极小 可忽略

              (3)仔细检查对资源的动态分配情况,来预防死锁

              (4)检测死锁并且恢复

              (5)避免死锁的一个通用的经验法则是:当几个线程都要访问共享资源A、B、C时,保证使每个线程都按照同样的顺序去访问它们,比如都先访问A,在访问B和C。这样不会产生闭环.

       参考:

        https://developer.apple.com/reference/dispatch#//apple_ref/c/func/dispatch_barrier_async

  • 相关阅读:
    bzoj4537: [Hnoi2016]最小公倍数
    bzoj4331: JSOI2012 越狱老虎桥
    bzoj4558: [JLoi2016]方
    bzoj4209: 西瓜王
    bzoj2653: middle
    bzoj4671: 异或图
    bzoj4771: 七彩树
    shell java应用启动脚本(app.sh)
    Springboot 构建http服务,返回的http行是'HTTP/1.1 200' 无状态码描述 客户端解析错误
    MariaDB(Mysql)-主从搭建
  • 原文地址:https://www.cnblogs.com/someonelikeyou/p/5910168.html
Copyright © 2020-2023  润新知