• iOS多线程-02-GCD


    简介


    • GCD(Grand Center Dispatch)是Apple为多核的并行运算提出的解决方案,纯C语言
    • 更加适配多核处理器,且自动管理线程的生命周期,使用起来较为方便
    • GCD通过任务和队列实现多线程功能
      • 任务:描述所要执行的操作
      • 队列:用来存放所要执行的任务,队列中的任务遵循FIFO(First In First Out)原则

    GCD的任务函数(是否开启新的线程)


    • 同步

      • 不具备开启新的线程的能力
      • 同步执行任务的函数
        • void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block),Block类型
          • queue:任务队列
          • block(代码块):所执行的任务
        • void dispatch_sync_f(dispatch_queue_t queue, void *context, dispatch_function_t work),函数类型(每个Block类型都对应一个函数类型)
          • queue:任务队列
          • context:传递给任务函数的参数
          • work(函数):所执行的任务
      • 同步执行任务的其他函数(barrier),在前面的任务执行完毕它才执行,它后边的任务等它执行完毕才执行
        • void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block),block类型
          • queue:任务队列,仅当该参数为并发队列时,该函数才有意义
        • dispatch_barrier_sync_f(dispatch_queue_t queue, void *context, dispatch_function_t work),函数类型
    • 异步

      • 具备开启新的线程的能力(需要将任务添加到并发队列中)
      • 异步执行任务的函数(参数意义与同步函数相同)
        • void dispatch_async(dispatch_queue_t queue, dispatch_block_t block)
        • void dispatch_async_f(dispatch_queue_t queue, void *context, dispatch_function_t work)
      • 异步执行任务的其他函数(barrier),在前面的任务执行完毕它才执行,它后边的任务等它执行完毕才执行(参数意义与同步函数相同)
        • void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block)
        • void dispatch_barrier_async_f(dispatch_queue_t queue, void *context, dispatch_function_t work)

    GCD的队列(任务的执行方式)


    • 并发队列
      • 开启多个线程,使队列中的多个任务并发执行(需要异步执行函数的配合)
    • 串行队列
      • 队列中的任务一个接一个顺序地执行
    • 队列的种类
      • 串行队列
        • dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
          • label:通常为0
          • attr:队列类型,DISPATCH_QUEUE_SERIAL
      • 并发队列
        • dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
          • label:通常为0
          • attr:队列类型 DISPATCH_QUEUE_CONCURRENT
      • 主队列(串行,只能在主线程中运行)
        • dispatch_queue_t dispatch_get_main_queue(void),获取主队列
      • 全局队列(并发)
        • dispatch_queue_t dispatch_get_global_queue(long identifier, unsigned long flags)

    任务与队列的组合


    • 同步函数
      • 同步函数主队列

        /**
        - 运行在主线程主队列(未开启新的线程),主线程被卡死
        - 原因:任务代码等待着当前函数执行完毕才能执行(当前函数正在执行且未执行完毕);
        	   当前函数等待着任务代码 执行完毕才能执行(当前任务正在执行且未执行完毕);
        	   相互等待,出现死锁
        */
        
        //获取主队列
        dispatch_queue_t queue = dispatch_get_main_queue();
        //添加任务到队列
        dispatch_sync(queue, ^{
            //任务1代码
        });
        dispatch_sync(queue, ^{
            //任务2代码
        });
        
      • 同步函数串行队列

        /**
        - 运行在主线程串行非主队列(未开启新的线程),任务串行执行
        */
        
        //创建串行队列
        dispatch_queue_t queue = dispatch_queue_create("com.23565@qq", DISPATCH_QUEUE_SERIAL);
        //添加任务到队列
        dispatch_sync(queue, ^{
            //任务1代码
        });
        dispatch_sync(queue, ^{
            //任务2代码
        });
        
      • 同步函数并发队列

        /**
        - 运行在非主线程并发队列(未开启新的线程),任务串行执行
        */
        
        //获取全局队列(并发)
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        //将任务加至队列
        dispatch_sync(queue, ^{
            //任务1代码
        });
        dispatch_sync(queue, ^{
            //任务2代码
        });
        
    • 异步函数
      • 异步函数主队列

        /**
        - 运行在主线程主队列(未开启新的线程),任务串行执行
        */
        
        // 获得主队列
        dispatch_queue_t queue = dispatch_get_main_queue();
        // 将任务加入队列
        dispatch_async(queue, ^{
            //任务1代码
        });
        dispatch_async(queue, ^{
            //任务2代码
        });
        
      • 异步函数串行队列

        /**
        - 运行在主函数串行非主队列(未开启新的线程),任务串行执行
        */
        
        //创建串行队列
        dispatch_queue_t queue = dispatch_queue_create("com.23565@qq", DISPATCH_QUEUE_SERIAL);
        //将任务加至队列
        dispatch_async(queue, ^{
            //任务1代码
        })
        dispatch_async(queue, ^{
            //任务2代码
        })
        
      • 异步函数并发队列

        /**
        - 运行在非主线程并发队列(开启新的线程),任务并发执行
        - 系统根据任务创建线程(无法确定任务执行在哪个线程)
        */
        
        //获得全局并发队列
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        //将任务加入队列
        dispatch_async(queue, ^{
            //任务1代码
        });
        dispatch_async(queue, ^{
            //任务2代码
        });
        

    线程之间的通信


    • 从主线程到子线程
      • 注意

        • 只有异步函数与并发队列的组合,才会开启新的线程,使任务并发执行
        • 通常使用异步函数将任务添加到并发队列中,来实现从主线程到子线程的通信
      • 实现代码

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        		//需要在子线程中执行的任务代码
        	})
        
    • 从子线程到主线程
      • 注意

        • 主队列中的任务只能在主线程中执行
        • 通常使用异步/同步函数将任务添加到主队列中,来实现从子线程到主线程的通信
      • 实现代码

        dispatch_async(dispatch_get_main_queue(), ^{
                //需要在主线程中执行的代码
            })
        

    GCD的其他任务


    • 单次执行(通常用在单例模式的设计中)

      //定义一个标记
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
          //此处的代码只会被执行一次
      });
      
    • 延迟执行

      /**
      - 方法一(GCD)
      */
      dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
          //此处的代码将延迟执行
      });
      
      /**
      - 方法二(performSelector)
      */
      [self performSelector:@selector(run) withObject:self afterDelay:2.0];
      
      /**
      - 方法三(NSTimer)
      */
      [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:NO]
      
      
    • 快速迭代

      void dispatch_apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t))
      /**
      	iterations:迭代执行的次数
      	queue:任务队列
      	block:迭代执行的代码
      	size_t:用来定义当前迭代到第几次,需要自己添加,如在size_t后添加index索引,记录当前的迭代次数
      */
      
    • Barrier

      /**
      - Barrier中的任务,只能在它前面的任务执行完毕才能执行
        Barrier后的任务,只能等到它执行完毕才能执行
      - 要将队列添加到自己创建的并发队列中,否其功能等同于函数
        void dispatch_async(dispatch_queue_t queue, dispatch_block_t block)
      */
      //创建队列(通常是自己创建的并发队列)
      dispatch_queue_t queue = dispatch_queue_create("123", DISPATCH_QUEUE_CONCURRENT);
      //将任务添加到队列
      dispatch_async(queue, ^{
          //在Barrier前执行的任务代码
      });
      dispatch_barrier_async(queue, ^{
         //Barrier中的任务代码
      });
      dispatch_async(queue, ^{
          //在Barrier后执行的任务代码
      });
      
    • 队列组

      //获取全局并发队列
      dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
      //创建队列组
      dispatch_group_t group = dispatch_group_create();
      //添加任务到队列组
      dispatch_group_async(group, queue, ^{
          	//任务1代码
      	});
      dispatch_group_async(group, queue, ^{
          	//任务2代码
      	});
      dispatch_group_notify(group, queue, ^{
          	//任务3代码
          	/**
          	group组中的所有任务执行完毕在执行
          	若group为空,则立即执行
          	*/
      });
      
    
    ##GCD定时器
    
    ---
    - 实现原理
    	- 创建一个DISPATCH_SOURCE_TYPE_TIMER类型的dispatch source,并添加到dispatch queue,通过dispatch source来响应事件
    	- 通过函数void dispatch_source_set_timer(dispatch_source_t source, dispatch_time_t start, uint64_t interval, uint64_t leeway),来设置dispatch source的执行事件
    	
    - 实现代码
    
    	```
    	//获得队列
    	dispatch_queue_t queue = dispatch_get_main_queue();
    	//创建一个定时器
        self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
        
        //设置定时器的各种属性(起止时间)
        dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(8.0 * NSEC_PER_SEC));
        uint64_t interval = (uint64_t)(1.0 * NSEC_PER_SEC);
        //设置
        dispatch_source_set_timer(self.timer, start, interval, 0);
        
        //设置回调
        dispatch_source_set_event_handler(self.timer, ^{
            //定时器被触发时所要执行的代码
        });
     
        //开启定时器
        dispatch_resume(self.timer);
        //取消定时器
        dispatch_cancel(self.timer);
    	```
  • 相关阅读:
    HTML元素解释
    Java命名规范
    HDU 1058 Humble Numbers(DP,数)
    HDU 2845 Beans(DP,最大不连续和)
    HDU 2830 Matrix Swapping II (DP,最大全1矩阵)
    HDU 2870 Largest Submatrix(DP)
    HDU 1421 搬寝室(DP)
    HDU 2844 Coins (组合背包)
    HDU 2577 How to Type(模拟)
    HDU 2159 FATE(二维完全背包)
  • 原文地址:https://www.cnblogs.com/theDesertIslandOutOfTheWorld/p/4759207.html
Copyright © 2020-2023  润新知