GCD-DISPATCH-多线程

近期在梳理多线程的知识点,那就先把系统API全部重新看下.
1. void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
   //在一个调度队列里面,提交一个异步执行的block
     
2. void dispatch_async_f(dispatch_queue_t queue,void *_Nullable context,dispatch_function_t work);
   //在一个调度队列里面提交一个异步执行的函数
    这个函数不经常用,看API解释
 * @param context
 * The application-defined context parameter to pass to the function.
 *
 * @param work
 * The application-defined function to invoke on the target queue. The first
 * parameter passed to this function is the context provided to
 * dispatch_async_f().
 * The result of passing NULL in this parameter is undefined.
 
   typedef void (*dispatch_function_t)(void *_Nullable);

queue不要为NULL,work不要为NULL,context是传参给work这个function,实验下.
- (void)testOne{
    dispatch_async_f(dispatch_get_global_queue(0, 0),(__bridge void * _Nullable)(@(9)),test);
}
void test(void *context) {

    NSLog(@"%@", context);
}
这个传参比较坑,必须是对象类型,刚开始测的时候用的是整型(int)数据的地址如,
int a,传参填的是&a,但是这样打印不是想要的结果,尝试如上解决,如果你可以用这种方式传参,请告诉我方法

3.dispatch_sync(dispatch_queue_t queue, DISPATCH_NOESCAPE dispatch_block_t block);
//在一个队列里,提交一个同步执行的block

4.dispatch_sync_f(dispatch_queue_t queue,void *_Nullable context,dispatch_function_t work);
//参考2



5. void dispatch_apply(size_t iterations, dispatch_queue_t queue,DISPATCH_NOESCAPE void (^block)(size_t));

这个函数没怎么用过,那我们看源码吧
void dispatch_apply(size_t iterations, dispatch_queue_t dq, void (^work)(size_t))
{
    dispatch_apply_f(iterations, dq, work,
            (dispatch_apply_function_t)_dispatch_Block_invoke(work));
}

void dispatch_apply_f(size_t iterations, dispatch_queue_t dq, void *ctxt,
        void (*func)(void *, size_t))
{
    if (unlikely(iterations == 0)) {
        return;
    }
    dispatch_thread_context_t dtctxt =
            _dispatch_thread_context_find(_dispatch_apply_key);
    size_t nested = dtctxt ? dtctxt->dtc_apply_nesting : 0;
    dispatch_queue_t old_dq = _dispatch_queue_get_current();

    if (likely(dq == DISPATCH_APPLY_AUTO)) {
        dq = _dispatch_apply_root_queue(old_dq);
    }
    dispatch_qos_t qos = _dispatch_priority_qos(dq->dq_priority);
    if (unlikely(dq->do_targetq)) {
        // if the queue passed-in is not a root queue, use the current QoS
        // since the caller participates in the work anyway
        qos = _dispatch_qos_from_pp(_dispatch_get_priority());
    }
    int32_t thr_cnt = (int32_t)_dispatch_qos_max_parallelism(qos,
            DISPATCH_MAX_PARALLELISM_ACTIVE);

    if (likely(!nested)) {
        nested = iterations;
    } else {
        thr_cnt = nested < (size_t)thr_cnt ? thr_cnt / (int32_t)nested : 1;
        nested = nested < DISPATCH_APPLY_MAX && iterations < DISPATCH_APPLY_MAX
                ? nested * iterations : DISPATCH_APPLY_MAX;
    }
    if (iterations < (size_t)thr_cnt) {
        thr_cnt = (int32_t)iterations;
    }
    struct dispatch_continuation_s dc = {
        .dc_func = (void*)func,
        .dc_ctxt = ctxt,
        .dc_data = dq,
    };
    dispatch_apply_t da = (typeof(da))_dispatch_continuation_alloc();
    da->da_index = 0;
    da->da_todo = iterations;
    da->da_iterations = iterations;
    da->da_nested = nested;
    da->da_thr_cnt = thr_cnt;
#if DISPATCH_INTROSPECTION
    da->da_dc = _dispatch_continuation_alloc();
    *da->da_dc = dc;
#else
    da->da_dc = &dc;
#endif
    da->da_flags = 0;

    if (unlikely(dq->dq_width == 1 || thr_cnt <= 1)) {
        return dispatch_sync_f(dq, da, _dispatch_apply_serial);
    }
    if (unlikely(dq->do_targetq)) {
        if (unlikely(dq == old_dq)) {
            return dispatch_sync_f(dq, da, _dispatch_apply_serial);
        } else {
            return dispatch_sync_f(dq, da, _dispatch_apply_redirect);
        }
    }

    dispatch_thread_frame_s dtf;
    _dispatch_thread_frame_push(&dtf, dq);
    _dispatch_apply_f2(dq, da, _dispatch_apply_invoke);
    _dispatch_thread_frame_pop(&dtf);
}
这是一个同步队列的循环,必须等到这个队列执行完毕才会跳出循环,这个循环不是按顺序执行的.

void dispatch_apply_f(size_t iterations, dispatch_queue_t queue,void *_Nullable context,void (*work)(void *_Nullable, size_t));
//参考以上内容分析,不做解释
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
//队列执行优先级

dispatch_queue_attr_make_initially_inactive(dispatch_queue_attr_t _Nullable attr);

dispatch_queue_attr_make_with_autorelease_frequency(dispatch_queue_attr_t _Nullable attr,dispatch_autorelease_frequency_t frequency);

dispatch_qos_class_t
/*
__QOS_ENUM(qos_class, unsigned int,
    QOS_CLASS_USER_INTERACTIVE
            __QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x21,
    QOS_CLASS_USER_INITIATED
            __QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x19,
    QOS_CLASS_DEFAULT
            __QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x15,
    QOS_CLASS_UTILITY
            __QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x11,
    QOS_CLASS_BACKGROUND
            __QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x09,
    QOS_CLASS_UNSPECIFIED
            __QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x00,
);
*/
dispatch_queue_attr_t dispatch_queue_attr_make_with_qos_class(
       dispatch_queue_attr_t _Nullable attr,
       dispatch_qos_class_t qos_class, int relative_priority);
//返回一个属性,适用于创建一个想要的服务质量信息的调度队列。主要用于dispatch_queue_create函数。

dispatch_queue_t dispatch_queue_create_with_target(const char *_Nullable label,
    dispatch_queue_attr_t _Nullable attr, dispatch_queue_t _Nullable target)
    DISPATCH_ALIAS_V2(dispatch_queue_create_with_target);
//创建队列

dispatch_queue_create(const char *_Nullable label,dispatch_queue_attr_t _Nullable attr);
//创建队列,attr值为DISPATCH_QUEUE_SERIAL,DISPATCH_QUEUE_CONCURRENT

dispatch_queue_get_label(dispatch_queue_t _Nullable queue);
//得到指定队列的标签,没有设定返回NULL

dispatch_queue_get_qos_class(dispatch_queue_t queue,int *_Nullable relative_priority_ptr);
//得到指定队列的服务质量优先级

void dispatch_set_target_queue(dispatch_object_t object,dispatch_queue_t _Nullable queue);
//给GCD对象设置目标队列,这个目标队列负责处理这个对象。
//https://www.cnblogs.com/denz/archive/2016/02/24/5214297.html


void dispatch_after(dispatch_time_t when,
    dispatch_queue_t queue,
    dispatch_block_t block);

void dispatch_after_f(dispatch_time_t when,
    dispatch_queue_t queue,
    void *_Nullable context,
    dispatch_function_t work);

void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
void dispatch_barrier_async_f(dispatch_queue_t queue,void *_Nullable context,dispatch_function_t work);

dispatch_queue_t concurrentQueue = dispatch_queue_create("my.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(concurrentQueue, ^(){
        NSLog(@"dispatch-1");
    });
    dispatch_async(concurrentQueue, ^(){
        NSLog(@"dispatch-2");
    });
    dispatch_barrier_async(concurrentQueue, ^(){
        NSLog(@"dispatch-barrier"); 
    });
    dispatch_async(concurrentQueue, ^(){
        NSLog(@"dispatch-3");
    });
    dispatch_async(concurrentQueue, ^(){
        NSLog(@"dispatch-4");
    });
dispatch_barrier_async 作用是在并行队列中,等待前面两个操作并行操作完成,这里是并行输出
dispatch-1,dispatch-2
然后执行
dispatch_barrier_async中的操作,(现在就只会执行这一个操作)执行完成后,即输出
"dispatch-barrier,
最后该并行队列恢复原有执行状态,继续并行执行
dispatch-3,dispatch-4

void dispatch_barrier_sync(dispatch_queue_t queue,DISPATCH_NOESCAPE dispatch_block_t block);
void dispatch_barrier_sync_f(dispatch_queue_t queue,void *_Nullable context,dispatch_function_t work);
dispatch_barrier_sync和dispatch_barrier_async的区别
参考:通过GCD中的dispatch_barrier_(a)sync加强对sync中所谓等待的理解

void dispatch_queue_set_specific(dispatch_queue_t queue, const void *key,void *_Nullable context, dispatch_function_t _Nullable destructor);
void *_Nullable dispatch_queue_get_specific(dispatch_queue_t queue, const void *key);
void *_Nullable dispatch_get_specific(const void *key);
指定队列设置标识和取出标识
用法参考
主线程中也不绝对安全的 UI 操作
告诉你dispatch_queue_set_specific和dispatch_get_specific是个什么鬼

void dispatch_assert_queue(dispatch_queue_t queue);

void dispatch_assert_queue_barrier(dispatch_queue_t queue);

void dispatch_assert_queue_not(dispatch_queue_t queue);

//这三个没找到用法,我自己也没用过

参考:
GCD源码
Grand Central Dispatch和Block使用-浅析
dispatch_apply浅析-相关文章也很好
细说GCD如何用
GCD
iOS之多线程GCD-经典

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355