美文网首页
深入理解GCD补充

深入理解GCD补充

作者: Scott丶Wang | 来源:发表于2018-03-05 18:12 被阅读35次

    先了解几个知识点
    联合结构我的理解是模板类,具有相同个数成员变量、成员函数的类(成员变量类型不同)
    union 维护足够的空间来置放多个数据成员中的“一种”,而不是为每一个数据成员配置空间,在union 中所有的数据成员共用一个空间,同一时间只能储存其中一个数据成员,所有的数据成员具有相同的起始地址

    typedef struct dispatch_object_s {
    private:
        dispatch_object_s();//构造函数
        ~dispatch_object_s();//析构函数
        dispatch_object_s(const dispatch_object_s &);//copy构造函数
        void operator=(const dispatch_object_s &);//重载等号操作符
    } *dispatch_object_t;
    
    typedef union {
        struct _os_object_s *_os_obj;
        struct dispatch_object_s *_do;
        struct dispatch_continuation_s *_dc;
        struct dispatch_queue_s *_dq;
        struct dispatch_queue_attr_s *_dqa;
        struct dispatch_group_s *_dg;
        struct dispatch_source_s *_ds;
        struct dispatch_mach_s *_dm;
        struct dispatch_mach_msg_s *_dmsg;
        struct dispatch_source_attr_s *_dsa;
        struct dispatch_semaphore_s *_dsema;
        struct dispatch_data_s *_ddata;
        struct dispatch_io_s *_dchannel;
        struct dispatch_operation_s *_doperation;
        struct dispatch_disk_s *_ddisk;
    } dispatch_object_t;
    

    以上列举的就是GCD涉及到的结构体,这些结构体有几个共同点就是指向真实结构为dispatch_object_t结构体,一个C++类型的结构体,里面除了/构造函数、析构函数、copy构造函数、重载等号操作符之外别无其他,这里可以理解为id类型,在有需要的情况下转成需要的结构。

    队列和线程的关系:

    gcd-pool.png
    https://www.objc.io/issues/2-concurrency/concurrency-apis-and-pitfalls/

    Grand Central Dispatch(GCD)是在OS X 10.6和iOS 4中引入的,目的是使开发人员更容易利用消费设备中越来越多的CPU内核。 我们将在article about low-level concurrency APIs.详细介绍GCD。
    使用GCD,您不再直接与线程交互。 相反,您可以将代码块添加到队列中,GCD在后台管理线程池。 GCD决定您的代码块将在哪个特定线程上执行,并根据可用的系统资源管理这些线程。 因为线程现在被集中管理并从应用程序开发者中抽象出来,这减少了太多的创建线程的问题,
    GCD的另一个重要变化是您作为开发人员现在考虑的是队列中的任务而不是线程。
    GCD公开了五个不同的队列:在主线程上运行的主队列,具有不同优先级的三个后台队列,以及具有更低优先级的I/O遏制的一个后台队列。 此外,您可以创建自定义队列,可以是串行队列或并发队列。 虽然自定义队列是一个强大的抽象,但您在其上调度的所有块最终将逐渐下移到系统的全局队列及其线程池。
    首先使用几个不同优先级的队列听起来非常简单。但是,我们强烈建议您在几乎所有情况下都使用默认优先级的队列。如果这些任务访问共享资源,则在具有不同优先级的队列上调度任务可能会很快导致意外的行为。这可能会导致整个程序停顿,因为一些低优先级的任务阻止高优先级的任务执行。你可以在下面读到更多关于这个现象的信息,叫做优先级反转。
    虽然GCD是一个低级的C API,但是使用起来却很简单。这让我们很容易忘记,在将块分派到GCD队列时,并发编程的所有注意事项和缺陷仍然适用。请务必阅读以下有关并发编程的挑战,以了解潜在的问题。此外,在这个问题中,我们有一个很好的演示GCD API,其中包含许多深入的解释和有价值的提示。

    define DISPATCH_QUEUE_SERIAL NULL
    define DISPATCH_QUEUE_CONCURRENT

    在创建queue的时候我们调用一下函数

    /**
     * 创建dispatch_queue_t队列
     * dispatch_queue_attr_t队列属性结构体,预定义的属性,例如DISPATCH_QUEUE_SERIAL,DISPATCH_QUEUE_CONCURRENT或调用dispatch_queue_attr_make_with_*函数的结果。
     */
    dispatch_queue_t
    dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
    
    参数解释
    通过dispatch_queue_create()函数来创建一个用于提交任务队列的时候,
    第二个参数传DISPATCH_QUEUE_SERIAL或NULL的时候都会创建一个串行队列;
    第二个参数传DISPATCH_QUEUE_CONCURRENT的时候,将这个宏展开的话最终会得到一个这样的结构体:
    
    #define DISPATCH_QUEUE_CONCURRENT ==> ((__bridge dispatch_queue_attr_t)&(object)) = { \
        .do_vtable = DISPATCH_VTABLE(queue_attr), \
        ._objc_isa = DISPATCH_OBJC_CLASS(queue_attr), \
        .do_ref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT, \
        .do_xref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT\
        .dqa_qos_and_relpri = (_dispatch_priority_make(QOS_CLASS_UNSPECIFIED, 0) & \
        DISPATCH_PRIORITY_REQUESTED_MASK), \
        .dqa_overcommit = _dispatch_queue_attr_overcommit_unspecified, \
        .dqa_autorelease_frequency = DISPATCH_AUTORELEASE_FREQUENCY_INHERIT, \
        .dqa_concurrent = (1), \
        .dqa_inactive = (false), \
    }
    
    /*!
     * @function dispatch_get_global_queue
     *
     * @abstract
     * 返回一个给定优先级、众所周知的全局并发队列
     * Returns a well-known global concurrent queue of a given quality of service
     * class.
     *
     * @discussion
     * The well-known global concurrent queues may not be modified. Calls to
     * dispatch_suspend(), dispatch_resume(), dispatch_set_context(), etc., will
     * have no effect when used with queues returned by this function.
     *
     * @param identifier
     * A quality of service class defined in qos_class_t or a priority defined in
     * dispatch_queue_priority_t.
     *
     * It is recommended to use quality of service class values to identify the
     * well-known global concurrent queues:
     *  - QOS_CLASS_USER_INTERACTIVE
     *  - QOS_CLASS_USER_INITIATED
     *  - QOS_CLASS_DEFAULT
     *  - QOS_CLASS_UTILITY
     *  - QOS_CLASS_BACKGROUND
     *
     * The global concurrent queues may still be identified by their priority,
     * which map to the following QOS classes:
     *  - DISPATCH_QUEUE_PRIORITY_HIGH:         QOS_CLASS_USER_INITIATED
     *  - DISPATCH_QUEUE_PRIORITY_DEFAULT:      QOS_CLASS_DEFAULT
     *  - DISPATCH_QUEUE_PRIORITY_LOW:          QOS_CLASS_UTILITY
     *  - DISPATCH_QUEUE_PRIORITY_BACKGROUND:   QOS_CLASS_BACKGROUND
     *
     * @param flags
     * 这个参数是预留以后使用的,传递除0之外的任何值都可能导致返回值为NULL
     *
     * @result
     * 如果请求的全局队列不存在,则返回所请求的全局队列或NULL。
     */
    dispatch_queue_t
    dispatch_get_global_queue(long identifier, unsigned long flags);
    
    
    #实现
    dispatch_queue_t
    dispatch_get_global_queue(long priority, unsigned long flags)
    {
        if (flags & ~(unsigned long)DISPATCH_QUEUE_OVERCOMMIT) {
            return DISPATCH_BAD_INPUT;
        }
        // 获得全局队列的优先级
        dispatch_qos_t qos = _dispatch_qos_from_queue_priority(priority);
        /*
         如果传进来的优先级不是DISPATCH_QUEUE_PRIORITY_BACKGROUND、DISPATCH_QUEUE_PRIORITY_NON_INTERACTIVE、DISPATCH_QUEUE_PRIORITY_LOW、DISPATCH_QUEUE_PRIORITY_DEFAULT、DISPATCH_QUEUE_PRIORITY_HIGH其中的一种,底层会调用_dispatch_qos_from_qos_class()函数创建优先级
         static inline dispatch_qos_t
         _dispatch_qos_from_queue_priority(long priority)
         {
             switch (priority) {
                 case DISPATCH_QUEUE_PRIORITY_BACKGROUND:      return DISPATCH_QOS_BACKGROUND;
                 case DISPATCH_QUEUE_PRIORITY_NON_INTERACTIVE: return DISPATCH_QOS_UTILITY;
                 case DISPATCH_QUEUE_PRIORITY_LOW:             return DISPATCH_QOS_UTILITY;
                 case DISPATCH_QUEUE_PRIORITY_DEFAULT:         return DISPATCH_QOS_DEFAULT;
                 case DISPATCH_QUEUE_PRIORITY_HIGH:            return DISPATCH_QOS_USER_INITIATED;
                 default: return _dispatch_qos_from_qos_class((qos_class_t)priority);
                 {
                     static inline dispatch_qos_t
                     _dispatch_qos_from_qos_class(qos_class_t cls)
                     {
                         switch ((unsigned int)cls) {
                             case QOS_CLASS_USER_INTERACTIVE: return DISPATCH_QOS_USER_INTERACTIVE;
                             case QOS_CLASS_USER_INITIATED:   return DISPATCH_QOS_USER_INITIATED;
                             case QOS_CLASS_DEFAULT:          return DISPATCH_QOS_DEFAULT;
                             case QOS_CLASS_UTILITY:          return DISPATCH_QOS_UTILITY;
                             case QOS_CLASS_BACKGROUND:       return DISPATCH_QOS_BACKGROUND;
                             case QOS_CLASS_MAINTENANCE:      return DISPATCH_QOS_MAINTENANCE;
                             default: return DISPATCH_QOS_UNSPECIFIED;
                         }
                     }
                 }
             }
         }
         */
        // 还是在获取优先级
    #if !HAVE_PTHREAD_WORKQUEUE_QOS
        if (qos == QOS_CLASS_MAINTENANCE) {
            qos = DISPATCH_QOS_BACKGROUND;
        } else if (qos == QOS_CLASS_USER_INTERACTIVE) {
            qos = DISPATCH_QOS_USER_INITIATED;
        }
    #endif
        if (qos == DISPATCH_QOS_UNSPECIFIED) {
            return DISPATCH_BAD_INPUT;
        }
        // 以上没有干任何事,就是为了单纯的回去优先级
        // overcommit用来控制线程数能不能超越物理内核数,显然通过该接口获得的队列不会给系统创建过多的队列
        // 前面接口的定义
        return _dispatch_get_root_queue(qos, flags & DISPATCH_QUEUE_OVERCOMMIT);
    }
    

    相关文章

      网友评论

          本文标题:深入理解GCD补充

          本文链接:https://www.haomeiwen.com/subject/rfjhfftx.html