Dispatch(semaphore+block+time)
Dispatch.h Semaphore.h //GCD信号资源量
dispatch_semaphore_t
是GCD中用来控制资源访问量的。共有三个函数
dispatch_semaphore_tdispatch_semaphore_create(long value);
//创建同时可用资源量。
longdispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
//设置可用资源超时时间
longdispatch_semaphore_signal(dispatch_semaphore_t dsema);
//解除对信号资源量的限制
- 对dispatch_semaphore_t的理解可以是:*
- 利用
dispatch_semaphore_create
创建系统可以同时使用的资源数,意思也就是临时对系统可用资源数添加一个限制。 -
dispatch_semaphore_wait
用这个函数设置一下对可用资源增加这个限制的时间。一般两个值DISPATCH_TIME_NOW
和DISPATCH_TIME_FOREVER
,也可以理解为临时降低系统可用资源的数量。 -
dispatch_semaphore_signal
发送一个信号解除对系统可用资源数量的限制。
总结一下:这三个函数有点像高速公路临时收费站,第一个函数增加一个收费站,也就是增加几个收费窗口,第二个函数也就是这个临时收费站有多久有效期,第三个函数相当于收费站上级给收费站发送的撤销通知。代码
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
//数字可以修改
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//时间可以修改你的需要被限制代码dispatch_semaphore_signal(semaphore);
Dispatch_time 两个函数
dispatch_time_t
dispatch_time(dispatch_time_t when, int64_t delta);
dispatch_time_t
dispatch_walltime(const struct timespec *_Nullable when, int64_t delta);
第一个函数 第一个参数是从什么时间开始,一般直接传 DISPATCH_TIME_NOW; 表示从现在开始
第二个参数表示具体的时间长度(不能直接传 int 或 float), 可以写成这种形式 (int64_t)3* NSEC_PER_SEC
#define NSEC_PER_SEC 1000000000ull每秒有1000000000纳秒
#define NSEC_PER_MSEC 1000000ull每毫秒有1000000纳秒
#define USEC_PER_SEC 1000000ull每秒有1000000微秒
#define NSEC_PER_USEC 1000ull每微秒有1000纳秒
注意 delta 的单位是纳秒!第二个函数 第一个参数是一个结构体, 创建的是一个绝对的时间点,比如 2016年10月10日8点30分30秒, 如果你不需要自某一个特定的时刻开始,可以传 NUll,表示自动获取当前时区的当前时间作为开始时刻, 第二参数意义同第一个函数
1秒的写作方式可以是 1* NSEC_PER_SEC; 1000* NSEC_PER_MSEC; USEC_PER_SEC* NSEC_PER_USEC
dispatch_time_t time = dispatch_walltime(NULL, 5* NSEC_PER_SEC);
。两个函数的不同
例如: 从现在开始,1小时之后是触发某个事件源引自CSDN博客顽儿去
使用第一个函数创建的是一个相对的时间,第一个参数开始时间参考的是当前系统的时钟,当 device 进入休眠之后,系统的时钟也会进入休眠状态, 第一个函数同样被挂起; 假如 device 在第一个函数开始执行后10分钟进入了休眠状态,那么这个函数同时也会停止执行,当你再次唤醒 device 之后,该函数同时被唤醒,但是事件的触发就变成了从唤醒 device 的时刻开始,1小时之后
而第二个函数则不同,他创建的是一个绝对的时间点,一旦创建就表示从这个时间点开始,1小时之后触发事件,假如 device 休眠了10分钟,当再次唤醒 device 的时候,计算时间间隔的时间起点还是 开始时就设置的那个时间点, 而不会受到 device 是否进入休眠影响
Dispatch_block
QOS_CLASS_T 质量服务等级,简单点就是优先级
DISPATCH_BLOCK_BARRIER
//提交并发队列时作为一个栅栏代码块使用,直接调用代码块的时候,这个参数没有任何作用DISPATCH_BLOCK_DETACHED
如果直接调用用这个flag创建的代码块,block代码块执行过程中将忽略调用线程之前给代码块添加的一些属性。本代码块执行过程中和质量服务等级无关,和属性无关和请求无关,如果这个代码块被提交到一个队列,那么它的执行和队列属性有关。DISPATCH_BLOCK_ASSIGN_CURRENT
用这个flag创建的代码块将被获得创建代码块时的上下文属性,如果直接使用这个block,那么它创建时获得的上下文属性等将在调用它的线程中可以使用,如果在一个队列中调用这个block,那么将会用提交时的上下文属性替换创建时的上下文属性。使用DISPATCH_BLOCK_NO_QOS_CLASS
和dispatch_block_create_with_qos_class()
方法指定的质量服务等级会优先级高于用这个flag指定的质量服务优先级DISPATCH_BLOCK_NO_QOS_CLASS
不指定质量服务优先级创建的block,直接使用这个block,这个block的质量服务优先级是由调用线程决定的,如果被提交到一个队列,将用提交时的质量服务级别替换相关的block实例的默认行为。创建的block用在函数dispatch_block_create_with_qos_class()
中,这个flag将被忽略。DISPATCH_BLOCK_INHERIT_QOS_CLASS
队列的质量服务优先级优先于block中用这个flag指定的优先级,本参数只有在队列没有指定质量服务优先级的时候才起作用,dispatch_block
提交到一个异步执行队列的时候使用默认是使用这个flag的(如果不是用dispatch_block创建的block),如果队列中指定DISPATCH_BLOCK_ENFORCE_QOS_CLASS
或者直接调用block,这个参数将不起作用。DISPATCH_BLOCK_ENFORCE_QOS_CLASS
block的质量服务优先级大于队列指定的质量服务优先级,队列中同步执行的block使用这个flag作为默认值,直接调用也是使用这个作为默认值。
dispatch_block_t
dispatch_block_create(dispatch_block_flags_t flags, dispatch_block_t block);
- 第一种创建block方式
用指定的flag值和block在堆区(copy的方式)创建一个新的block,新的block可以通过dispatch_async()调用或者直接调用,可以被调用任意次数,但是只有第一次能被dispatch_block_wait()等待和dispatch_block_notify()观察
如果新创建的block被提交到一个队列,除非block是用DISPATCH_BLOCK_ASSIGN_CURRENT,DISPATCH_BLOCK_NO_QOS_CLASS,DISPATCH_BLOCK_DETACHED创建的,否则它的质量服务优先级都由创建这个block时指定的flag决定。
新创建的block执行时的质量服务优先级同时取决于队列的QOS 和 创建block时的flag,
dispatch_block_texcutBlock = dispatch_block_create(DISPATCH_BLOCK_BARRIER, ^{
NSLog(@"perform blockwithonly one");
});
- 第二种创建block方式
直接调用的时候只要只要创建的时候的QOS不会导致调用线程的QOS变低就行。
如果新创建的block被提交到一个串行队列并且被指定了QOS,系统将尽可能的用必要的qos覆盖来确保这个提交到串行队列的block在同等级的qos或者更高的qos等级执行。
qos传QOS_CLASS_UNSPECIFIED和指定block的flag为DISPATCH_BLOCK_NO_QOS_CLASS效果一样,传其他值将导致返回的block为空。
relative_priority 是一个负的便宜量,如果指定一个大于0 小于QOS_MIN_RELATIVE_PRIORITY(一个宏定义值为-15)的值将导致创建出来的block为null
block 用来创建新block的原始block
dispatch_block_ttestBlock =dispatch_block_create_with_qos_class(DISPATCH_BLOCK_NO_QOS_CLASS, QOS_CLASS_UNSPECIFIED, -10, ^{
NSLog(@"这是dispatch_block_create_with_qos_class创建的block");
});
testBlock();
//直接调用
同步阻塞线程,直到传入的block执行完成或者时间过期(也就是传入的时间参数过期了)
dispatch_block_wait(testBlock, DISPATCH_TIME_FOREVER);
给被执行的block添加一个通知block,当被执行的block执行完成之后会自动调用通知block
dispatch_block_notify(testBlock, dispatch_get_main_queue(), ^{
NSLog(@"notificationBlock");
});
【Dispatch(semaphore+block+time)】只能取消还没有执行的block,已经在执行的block不能被取消
dispatch_block_cancel(testBlock);
推荐阅读
- View·dispatchTouchEvent|View·dispatchTouchEvent 源码分析(四)
- RCTBridge|RCTBridge required dispatch_sync to load RCTDevLoadingView. This may lead to deadlocks
- 总结一点IDispatch|总结一点IDispatch error 的原因
- COM学习笔记8_IDispatch (调度接口) 自动化
- C++ COM中IDispatch之Invoke获取对象时,注意点
- echarts中国地图+自定义tooltip样式+dispatchAction()方法实现联动
- “过时”的SpringMVC我们到底在用什么(深入分析DispatchServlet源码)
- 解决spring boot与cxf集成报找不到DispatcherServletPath的问题
- SpringMVC配拦截器报错[dispatcherServlet]:Servlet.service() for servlet [dispatcherServlet] threw exception
- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatch