我的上篇文章iOS中多个网络请求的同步问题总结中用到了dispatch_group来进行线程同步,对用法不是特别熟悉所以整理这篇文章来加深记忆(闲着也是闲着)

一、简单介绍下将会用到的一些东西

英语不好就不翻译官方文档了..

1、dispatch_group_async

* Submits a block to a dispatch queue and associates the block with the given
* dispatch group
//将一个block(代码块)加入到dispatch_queue_t queue中并和dispatch_group_t group相关联
void dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);

个人理解:将代码块dispatch_block_t block放入队列dispatch_queue_t queue中执行;并和调度组dispatch_group_t group相互关联;如果提交到dispatch_queue_t queue中的block全都执行完毕会调用dispatch_group_notify并且dispatch_group_wait会停止等待;

2、dispatch_group_enter(group)、dispatch_group_leave(group)

* Calling this function indicates another block has joined the group through
* a means other than dispatch_group_async(). Calls to this function must be
* balanced with dispatch_group_leave().
调用这个方法标志着一个代码块被加入了group,和dispatch_group_async功能类似;dispatch_group_enter()、dispatch_group_leave()必须成对出现
void dispatch_group_enter(dispatch_group_t group);

个人理解:和内存管理的引用计数类似,我们可以认为group也持有一个整形变量(只是假设),当调用enter时计数加1,调用leave时计数减1,当计数为0时会调用dispatch_group_notify并且dispatch_group_wait会停止等待;

3、dispatch_group_notify

void dispatch_group_notify(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);

个人理解:当关联到dispatch_group_t上的dispatch_group_async任务执行完毕或者是关联在上面的dispatch_group_enter、dispatch_group_leave成对出现了。参数中的dispatch_block_t block会被提交到dispatch_queue_t queue中执行。

4、dispatch_group_wait

long dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout);

个人理解:和dispatch_group_notify功能类似(多了一个dispatch_time_t参数可以设置超时时间),在group上任务完成前,dispatch_group_wait会阻塞当前线程(所以不能放在主线程调用)一直等待;当group上任务完成,或者等待时间超过设置的超时时间会结束等待;

二、dispatch_group_async代码示例

- (void)groupSync
{
dispatch_queue_t disqueue = dispatch_queue_create("com.shidaiyinuo.NetWorkStudy", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t disgroup = dispatch_group_create();
dispatch_group_async(disgroup, disqueue, ^{ NSLog(@"任务一完成");
}); dispatch_group_async(disgroup, disqueue, ^{ sleep(8);
NSLog(@"任务二完成");
}); dispatch_group_notify(disgroup, disqueue, ^{ NSLog(@"dispatch_group_notify 执行");
}); dispatch_async(dispatch_get_global_queue(0, 0), ^{ dispatch_group_wait(disgroup, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC));
NSLog(@"dispatch_group_wait 结束");
});
}

向group中放入两个任务(准确讲是将任务加入到了并行队列disqueue中执行,然后队列和group关联当队列上任务执行完毕时group会进行同步),第二个任务会等待8秒所以第一个任务会先完成;会先打印任务一完成再打印任务二完成,当两个任务都完成时dispatch_group_notify中的block会执行;会接着打印dispatch_group_notify 执行;dispatch_group_wait设置了超时时间为5秒所以它会在5秒后停止等待打印dispatch_group_wait 结束(任务二会等待8秒所以它会在任务二完成前打印);

 
测试输出结果

需要注意的:dispatch_group_wait是同步的所以不能放在主线程执行。
补充: dispatch_group会等和它关联的所有的dispatch_queue_t上的任务都执行完毕才会发出同步信号(dispathc_group_notify的代码块block会被执行,group_wati会结束等待)。也就是说一个group可以关联多个任务队列;下面给出示例:

- (void)groupSync2
{
dispatch_queue_t dispatchQueue = dispatch_queue_create("ted.queue.next1", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
dispatch_group_t dispatchGroup = dispatch_group_create();
dispatch_group_async(dispatchGroup, dispatchQueue, ^(){ sleep(5);
NSLog(@"任务一完成");
});
dispatch_group_async(dispatchGroup, dispatchQueue, ^(){ sleep(6);
NSLog(@"任务二完成");
}); dispatch_group_async(dispatchGroup, globalQueue, ^{ sleep(10);
NSLog(@"任务三完成");
}); dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^(){
NSLog(@"notify:任务都完成了");
});
}

上面的代码里有两个队列一个是我自己创建的并行队列dispatchQueue,另一个是系统提供的并行队列globalQueue;dispatch_group_notify会等这两个队列上的任务都执行完毕才会执行自己的代码块。

 
多个队列执行结果

三、dispatch_group_enter、dispatch_group_level示例

和dispatch_async相比,当我们调用n次dispatch_group_enter后再调用n次dispatch_group_level时,dispatch_group_notify和dispatch_group_wait会收到同步信号;这个特点使得它非常适合处理异步任务的同步当异步任务开始前调用dispatch_group_enter异步任务结束后调用dispatch_group_leve
下面是代码示例:

- (void)groupSync
{
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
dispatch_async(dispatch_get_global_queue(0, 0), ^{ sleep(5);
NSLog(@"任务一完成");
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(dispatch_get_global_queue(0, 0), ^{ sleep(8);
NSLog(@"任务二完成");
dispatch_group_leave(group);
});
dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{ NSLog(@"任务完成");
});
}

示例代码中在global_queue上执行sleep任务模拟网络请求。

 
控制台打印结果

补充: 如果像最后一个示例那样,block里执行的是同步类型的代码那么用dispatch_group_async一样可以达到同步的效果,但是异步任务就不行了如下:

- (void)groupSync2
{
dispatch_queue_t dispatchQueue = dispatch_queue_create("ted.queue.next1", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
dispatch_group_t dispatchGroup = dispatch_group_create();
dispatch_group_async(dispatchGroup, dispatchQueue, ^(){ dispatch_async(globalQueue, ^{ sleep(5);
NSLog(@"任务一完成");
});
});
dispatch_group_async(dispatchGroup, dispatchQueue, ^(){ dispatch_async(globalQueue, ^{ sleep(8);
NSLog(@"任务二完成");
});
});
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^(){
NSLog(@"notify:任务都完成了");
});
}

如果dispatch_group_async里执行的是异步代码dispatch_group_notify会直接触发而不会等待异步任务完成,而dispatch_group_enter、和dispatch_group_leave则不会有这个问题,它们只需要在任务开始前enter结束后leave即可达到线程同步的效果。


作者:liang1991
链接:https://www.jianshu.com/p/228403206664
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

使用dispatch_group来进行线程同步的更多相关文章

  1. [ 高并发]Java高并发编程系列第二篇--线程同步

    高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...

  2. C#多线程之线程同步篇3

    在上一篇C#多线程之线程同步篇2中,我们主要学习了AutoResetEvent构造.ManualResetEventSlim构造和CountdownEvent构造,在这一篇中,我们将学习Barrier ...

  3. C#多线程之线程同步篇2

    在上一篇C#多线程之线程同步篇1中,我们主要学习了执行基本的原子操作.使用Mutex构造以及SemaphoreSlim构造,在这一篇中我们主要学习如何使用AutoResetEvent构造.Manual ...

  4. C#多线程之线程同步篇1

    在多线程(线程同步)中,我们将学习多线程中操作共享资源的技术,学习到的知识点如下所示: 执行基本的原子操作 使用Mutex构造 使用SemaphoreSlim构造 使用AutoResetEvent构造 ...

  5. C# 线程同步的三类情景

    C# 已经提供了我们几种非常好用的类库如 BackgroundWorker.Thread.Task等,借助它们,我们就能够分分钟编写出一个多线程的应用程序. 比如这样一个需求:有一个 Winform ...

  6. Java进击C#——语法之线程同步

    上一章我们讲到关于C#线程方向的应用.但是笔者并没有讲到多线程中的另一个知识点--同步.多线程的应用开发都有可能发生脏数据.同步的功能或多或少都会用到.本章就要来讲一下关于线程同步的问题.根据笔者这几 ...

  7. Java多线程 3 线程同步

    在之前,已经学习到了线程的创建和状态控制,但是每个线程之间几乎都没有什么太大的联系.可是有的时候,可能存在多个线程多同一个数据进行操作,这样,可能就会引用各种奇怪的问题.现在就来学习多线程对数据访问的 ...

  8. JAVA之线程同步的三种方法

    最近接触到一个图片加载的项目,其中有声明到的线程池等资源需要在系统中线程共享,所以就去研究了一下线程同步的知识,总结了三种常用的线程同步的方法,特来与大家分享一下.这三种方法分别是:synchroni ...

  9. 三、线程同步之Sysnchronized关键字

    线程同步 问题引入 观察一面一段小程序: public class Main { private static int amount = 0; public static void main(Stri ...

随机推荐

  1. 移动端 华为手机 input中placeholder垂直居中失效

    为一个app写了一个嵌套的提现页面,效果如下图 input给定宽高,给了line-heigh,在浏览器查看效果正常,placeholder内容以及光标显示都是垂直居中的, IOS显示正常, Andro ...

  2. DB2查看表空间和增加表空间容量

    Db2 connect to xxx Db2 “LIST TABLESPACES SHOW DETAIL” Tablespace ID = 7 Name = TSASNAA Type = Databa ...

  3. SQL like查询条件中的通配符处理

    1. SQL like对时间查询的处理方法 SQL数据表中有savetime(smalldatetime类型)字段,表中有两条记录,savetime值为:2005-3-8 12:12:00和2005- ...

  4. C/C++中的函数指针

    C/C++中的函数指针 一.引子 今天无聊刷了leetcode上的一道题,如下: Median is the middle value in an ordered integer list. If t ...

  5. 学Arduino 需要做哪些准备?(引自"知乎用户:郑兴芳,DhP"的回答)

    本人非电子专业,使用Arduino完全出于兴趣,目前主要用于实验过程中的自动化操作. 一.基础准备主要是看一些入门介绍的电子文档,如Arduino_Basic.PDF.ArduinoL2.PDF .& ...

  6. Unity 点击屏幕发射射线 代码

    1,创建一根射线 2,检查射线与其他物体的碰撞,得到碰撞信息 3,通过碰撞信息对碰撞到的物体进行处理 using System.Collections; using System.Collection ...

  7. D. Destruction of a Tree_dfs序_性质分析_思维题

    题意: 给定一棵树,每次可以拆掉一个树上度数为偶数的点,拆掉该点后,与该点所连的所有边都会被删掉.问,是否有一种删点顺序可以删掉所有的点.如果有,则输出任意一组解. 数据范围:线性做法 O(n)O(n ...

  8. 路飞学城Python-Day50

    05-运算符 常用运算符 算数运算符 赋值运算符 比较运算符 逻辑运算符         // 赋值运算符          var money = prompt('请输入金额');          ...

  9. SPOJ CIRU

    SPOJ CIRU 题意 给出n个圆,求他们覆盖的面积. 解法 自适应Simpson,但需要将圆离散化一下,以保证我们查询的是一个连续的有圆的区间. 奇怪的是我没有离散化,样例都没有过,却把题给A了 ...

  10. ubuntu18.04crontab定时任务不执行

    环境介绍: 本人使用python写了一个自动化提交巡检的脚本放在服务器上,使用crontab去执行脚本的时候动作并没有执行,查看crontab日志时也不存在这个日志文件.如何如排查呢? 解决方案: 步 ...