zoukankan      html  css  js  c++  java
  • iOS多线程-多线程实现之GCD

    • 什么是GCD?

      • GCD: Grand Central Dispatch (重要的中枢调度器)
      • GCD是纯C语言的, 学习它就是学习一些函数的使用.
    • GCD的核心概念和使用步骤

      • 核心概念
        • 任务 : 执行什么操作
        • 队列 : 用于存放任务. 队列决定了队列中任务的执行方式
          • 队列又分为:
            • 并行队列 : 可以多个任务同时执行.
            • 串行队列 : 一次只能执行一个任务, 执行完一个任务才能执行下一个任务.
            • 主队列: 特殊的串行队列,这个后面会细说. 只要记住,主队列中的任务,在主线程中执行.
      • 使用步骤
        • 1.确定任务
        • 2.将任务添加到队列中,GCD会自动将队列中的任务取出,放到对应的线程中执行
          注意:任务取出遵守队列的FIFO(First Input First Output)原则:先进先出,后进后出
    • GCD执行任务的两个函数

      • 同步函数 : dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
        • queue :队列
        • block : 回调block,也就是上面所说的任务
        • 使用同步函数的任务是在当前线程中执行,同步函数没有创建新线程的能力
        • 注意点:如果是同步函数,只要是代码执行到同步函数哪一行,就会立即执行block,执行完之后才会继续往下执行
      • 异步函数 : dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
        • queue :队列
        • block : 回调block,也就是上面所说的任务
        • 使用异步函数的任务是在新的线程中执行,同步函数具有创建新线程的能力(具体创建多少个线程,是由系统决定的)

    总结

    • 同步函数: 在当前线程中执行任务,没有创建新线程的能力
    • 异步函数: 在新线程中执行任务,具有创建新线程的能力
    • 串行队列: 一次只能执行一个任务,执行完毕后才能执行下一个任务
    • 并行队列: 可以多个任务同时执行
    • 两种函数执行不同队列的效果

      • 同步函数:
        • 使用并行队列,在当前线程中一个一个的执行
        • 使用串行队列,在当前线程中一个一个的执行
        • 使用主队列,在主线程中一个一个的执行.注意:如果当前线程就是主线程的话会发生死锁
      • 异步函数:
        • 使用并行队列,创建多个子线程执行任务.
        • 使用串行队列,创建一个子线程,在子线程中一个一个的执行(具体创建多少个线程,是由系统决定的)
        • 使用主队列,在主线程中一个一个的执行.如果当前是主线程的话并不会发生死锁

    废话不多说,上代码

    //
    //  ViewControllerGCD.m
    //  GCD使用
    //
    //  Created by 雨轩 on 16/1/25.
    //  Copyright © 2016年 apple. All rights reserved.
    //
    
    #import "ViewControllerGCD.h"
    
    @implementation ViewControllerGCD
    
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
        NSLog(@"======================同步函数======================");
    
        [self syncToALLQueue];
    
        NSLog(@"======================我是一条可爱的分割线======================");
        NSLog(@"======================异步函数======================");
    
        [self asyncToALLQueue];
    }
    
    //异步函数搭配不同的队列
    - (void)asyncToALLQueue{
    
    /****************************************************并行队列****************************************************/
    
        //方式一:创建一个队列
        /*
         第一个参数:队列的名称
         第二个参数:队列的类型
                DISPATCH_QUEUE_SERIAL 串行队列(让任务一个接着一个执行)
                DISPATCH_QUEUE_CONCURRENT 并发队列(可以让多个任务并发执行,自动开启多个线程执行,执行异步函数中才有效果)
         */
        dispatch_queue_t concurrentQueue1 = dispatch_queue_create("yuxuan", DISPATCH_QUEUE_CONCURRENT);
    
        //方式二:获取GCD提供的一个全局的并行队列
        /*
        第一个参数:IOS8之前代表线程的优先级 / IOS8之后代表的是服务质量 (一般写0)
        IO8之前的取值                               IOS8之后的取值
        *  - DISPATCH_QUEUE_PRIORITY_HIGH(2)       QOS_CLASS_USER_INTERACTIVE 用户交互(用户迫切的执行任务,不要在这种服务质量下做耗时操作)
        *  - DISPATCH_QUEUE_PRIORITY_DEFAULT(0)            QOS_CLASS_DEFAULT   默认(重置队列)
        *  - DISPATCH_QUEUE_PRIORITY_LOW(-2)               QOS_CLASS_UTILITY   实用工具(耗时操作放在这里)
        *  - DISPATCH_QUEUE_PRIORITY_BACKGROUND(-32768)    QOS_CLASS_BACKGROUND
                                                           QOS_CLASS_UNSPECIFIED 用户需要
                                                           QOS_CLASS_USER_INITIATED    没有设置任务优先级
    
        第二个参数:系统保留的占位参数,永远写0
        */
        dispatch_queue_t concurrentQueue2 = dispatch_get_global_queue(0, 0);
    
    /****************************************************串行队列****************************************************/
    
        /*
         第一个参数:队列的名称
         第二个参数:队列的类型
         DISPATCH_QUEUE_SERIAL 串行队列(让任务一个接着一个执行)
         DISPATCH_QUEUE_CONCURRENT 并发队列(可以让多个任务并发执行,自动开启多个线程执行,执行异步函数中才有效果)
         */
        dispatch_queue_t serialQueue = dispatch_queue_create("yuxuan", DISPATCH_QUEUE_SERIAL);
    
    
    /****************************************************主队列****************************************************/
        //调用函数直接获取
        dispatch_queue_t mainQueue = dispatch_get_main_queue();
    
    
    /****************************************************添加任务****************************************************/
    
        //异步函数
        dispatch_async(mainQueue, ^{
    
            NSLog(@"任务1==========%@",[NSThread currentThread]);
    
        });
    
        //异步函数
        dispatch_async(mainQueue, ^{
    
            NSLog(@"任务2==========%@",[NSThread currentThread]);
    
        });
    
        //异步函数
        dispatch_async(mainQueue, ^{
    
            NSLog(@"任务3==========%@",[NSThread currentThread]);
    
        });
    
        //异步函数
        dispatch_async(mainQueue, ^{
    
            NSLog(@"任务4==========%@",[NSThread currentThread]);
    
        });
    
    }
    
    //同步函数搭配不同的队列
    - (void)syncToALLQueue{
    
        /****************************************************并行队列****************************************************/
    
        //方式一:创建一个队列
        /*
         第一个参数:队列的名称
         第二个参数:队列的类型
         DISPATCH_QUEUE_SERIAL 串行队列(让任务一个接着一个执行)
         DISPATCH_QUEUE_CONCURRENT 并发队列(可以让多个任务并发执行,自动开启多个线程执行,执行异步函数中才有效果)
         */
        dispatch_queue_t concurrentQueue1 = dispatch_queue_create("yuxuan", DISPATCH_QUEUE_CONCURRENT);
    
        //方式二:获取GCD提供的一个全局的并行队列
        /*
         第一个参数:IOS8之前代表线程的优先级 / IOS8之后代表的是服务质量 (一般写0)
         IO8之前的取值                               IOS8之后的取值
         *  - DISPATCH_QUEUE_PRIORITY_HIGH(2)       QOS_CLASS_USER_INTERACTIVE 用户交互(用户迫切的执行任务,不要在这种服务质量下做耗时操作)
         *  - DISPATCH_QUEUE_PRIORITY_DEFAULT(0)            QOS_CLASS_DEFAULT   默认(重置队列)
         *  - DISPATCH_QUEUE_PRIORITY_LOW(-2)               QOS_CLASS_UTILITY   实用工具(耗时操作放在这里)
         *  - DISPATCH_QUEUE_PRIORITY_BACKGROUND(-32768)    QOS_CLASS_BACKGROUND
         QOS_CLASS_UNSPECIFIED 用户需要
         QOS_CLASS_USER_INITIATED    没有设置任务优先级
    
         第二个参数:系统保留的占位参数,永远写0
         */
        dispatch_queue_t concurrentQueue2 = dispatch_get_global_queue(0, 0);
    
        /****************************************************串行队列****************************************************/
    
        /*
         第一个参数:队列的名称
         第二个参数:队列的类型
         DISPATCH_QUEUE_SERIAL 串行队列(让任务一个接着一个执行)
         DISPATCH_QUEUE_CONCURRENT 并发队列(可以让多个任务并发执行,自动开启多个线程执行,执行异步函数中才有效果)
         */
        dispatch_queue_t serialQueue = dispatch_queue_create("yuxuan", DISPATCH_QUEUE_SERIAL);
    
    
        /****************************************************主队列****************************************************/
        //调用函数直接获取
        dispatch_queue_t mainQueue = dispatch_get_main_queue();
    
    
        /****************************************************添加任务****************************************************/
    
        //异步函数
        dispatch_sync(mainQueue, ^{
    
            NSLog(@"任务1==========%@",[NSThread currentThread]);
    
        });
    
        //异步函数
        dispatch_sync(mainQueue, ^{
    
            NSLog(@"任务2==========%@",[NSThread currentThread]);
    
        });
    
        //异步函数
        dispatch_sync(mainQueue, ^{
    
            NSLog(@"任务3==========%@",[NSThread currentThread]);
    
        });
    
        //异步函数
        dispatch_sync(mainQueue, ^{
    
            NSLog(@"任务4==========%@",[NSThread currentThread]);
    
        });
    
    }
    
    @end
    异步函数和同步函数搭配并行队列的打印日志:当前线程是主线程
    • 异步函数:创建了多个子线程,并行(一起)执行
    • 同步函数:在当前线程(主线程)中一个一个的执行

      Paste_Image.png
    异步函数和同步函数搭配串行队列的打印日志:当前线程是主线程
    • 异步函数: 在新线程(子线程)中一个一个的执行.
    • 同步函数: 在当前线程中一个一个的执行.

      Paste_Image.png
    异步函数和同步函数搭配主队列的打印日志: 当前线程是主线程
    • 在syncToALLQueue方法中发生了死锁.同步函数使用主队列时,如果当前线程是主线程的话会发生死锁.
      • 原因:同步函数,只要是代码执行到同步函数哪一行,就会立即执行block,执行完之后才会继续往下执行.但是此时的主线程正在处理同步函数这个函数,但是主队列中的任务又必须在主线程中执行,这个时候block任务就会一直在等着主线程,而同步函数又一直在等着block任务执行完.这样就发生了我们所说的死锁情况.

        Paste_Image.png
      • 代码修改,解决死锁问题

    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        //把代码封装到子线程中执行, 解决同步函数使用主队列死锁问题
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"======================同步函数======================");
    
            [self syncToALLQueue];
    
            NSLog(@"======================我是一条可爱的分割线======================");
            NSLog(@"======================异步函数======================");
    
            [self asyncToALLQueue];
    
        }); 
      }
    • 这样就解决了死锁问题,因为当前线程不再是主线程了.

      Paste_Image.png

    GCD中实现线程间的通信

    • GCD实现线程间的通信非常简单,直接在函数里嵌套函数就行了
      代码如下:

      //线程间的通信
      -(void)threadsCommunicate{
      //在子线程中执行耗时操作
      dispatch_async(dispatch_get_global_queue(0, 0), ^{
          //耗时操作......
      
          //通知主线程,执行操作(比如刷新UI)
          //这种情况下使用异步函数或使用同步函数,效果是一样的都是在主线程中执行,并且当前线程不是主线程,并不会发生死锁
          dispatch_async(dispatch_get_main_queue(), ^{
              // 刷新UI
          });
      });
      }




    原文链接:http://www.jianshu.com/p/efa69b932883

  • 相关阅读:
    METHODS OF AND APPARATUS FOR USING TEXTURES IN GRAPHICS PROCESSING SYSTEMS
    Display controller
    Graphics processing architecture employing a unified shader
    Graphics-Processing Architecture Based on Approximate Rendering
    Architectures for concurrent graphics processing operations
    Procedural graphics architectures and techniques
    DYNAMIC CONTEXT SWITCHING BETWEEN ARCHITECTURALLY DISTINCT GRAPHICS PROCESSORS
    Thermal zone monitoring in an electronic device
    System and method for dynamically adjusting to CPU performance changes
    Framework for Graphics Animation and Compositing Operations
  • 原文地址:https://www.cnblogs.com/it-k-50/p/6117446.html
Copyright © 2011-2022 走看看