GCD下的几种实现同步的方式
GCD多线程下,实现线程同步的方式有如下几种:
1.串行队列 2.并行队列 3.分组 4.信号量
实例: 去网上获取一张图片并展示在视图上. 实现这个需求,可以拆分成两个任务,一个是去网上获取图片,一个是展示在视图上. 这两个任务是有关联的,所以需要同步处理.
下面看这几种方式如何实现.
一、
1.串行队列
1.1[GCD相关:]
(1)GCD下的dispatch_queue队列都是FIFO队列,都会按照提交到队列的顺序执行.
只是根据队列的性质,分为<1>串行队列:用户队列、主线程队列 <2>并行队列.
(2)同步(dispatch_sync)、异步方式(dispatch_async). 配合串行队列和并行队列使用.
1.2同步队列直接提交两个任务就可以.
// 串形队列
dispatch_queue_t serilQueue = dispatch_queue_create("com.quains.myQueue", 0); //开始时间
NSDate *startTime = [NSDate date]; __block UIImage *image = nil; //1.先去网上下载图片
dispatch_async(serilQueue, ^{
NSString *urlAsString = @"http://avatar.csdn.net/B/2/2/1_u010013695.jpg";
NSURL *url = [NSURL URLWithString:urlAsString]; NSError *downloadError = nil; NSData *imageData = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url] returningResponse:nil error:&downloadError]; if (downloadError == nil && imageData != nil) {
image = [[UIImage imageWithData:imageData] retain];
}
else if(downloadError != nil){
NSLog(@"error happened = %@", downloadError);
}
else{
NSLog(@"No data download");
}
}); //2.在主线程展示到界面里
dispatch_async(serilQueue, ^{ NSLog(@"%@",[NSThread currentThread]); // 在主线程展示
dispatch_async(dispatch_get_main_queue(), ^{
if (image != nil) { UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds]; [imageView setImage:image]; [imageView setContentMode:UIViewContentModeScaleAspectFit];
[self.view addSubview:imageView];
[imageView release]; NSDate *endTime = [NSDate date];
NSLog(@"串行异步 completed in %f time", [endTime timeIntervalSinceDate:startTime]);
}
else{
NSLog(@"image isn't downloaded, nothing to display");
}
}); }); //3.清理
dispatch_release(serilQueue);
[image release];
注意:
(1) __block变量分配在栈,retain下,防止被回收.
(2)dispatch要手动create和release.
(3)提交到主线程队列的时候,慎用同步dispatch_sync方法,有可能造成死锁. 因为主线程队列是串行队列,要等队列里的任务一个一个执行.所以提交一个任务到队列,如果用同步方法就会阻塞住主线程,而主线程又要等主线程队列里的任务都执行完才能执行那个刚提交的,所以主线程队列里还有其他的任务的话,但他已经被阻塞住了,没法先完成队列里的其他任务,即,最后一个任务也没机会执行到,于是造成死锁.
(4)提交到串行队列可以用同步方式,也可以用异步方式.
2.并行队列
采用并行队列的时候,可以采用同步的方式把任务提交到队列里去,即可以实现同步的方式
//新建一个队列
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //记时
NSDate *startTime = [NSDate date]; //加入队列
dispatch_async(concurrentQueue, ^{
__block UIImage *image = nil; //1.先去网上下载图片
dispatch_sync(concurrentQueue, ^{
NSString *urlAsString = @"http://avatar.csdn.net/B/2/2/1_u010013695.jpg";
NSURL *url = [NSURL URLWithString:urlAsString]; NSError *downloadError = nil; NSData *imageData = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url] returningResponse:nil error:&downloadError]; if (downloadError == nil && imageData != nil) {
image = [UIImage imageWithData:imageData];
}
else if(downloadError != nil){
NSLog(@"error happened = %@", downloadError);
}
else{
NSLog(@"No data download");
}
}); //2.在主线程展示到界面里
dispatch_sync(dispatch_get_main_queue(), ^{
if (image != nil) {
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
[imageView setImage:image]; [imageView setContentMode:UIViewContentModeScaleAspectFit];
[self.view addSubview:imageView];
[imageView release]; NSDate *endTime = [NSDate date];
NSLog(@"并行同步 completed in %f time", [endTime timeIntervalSinceDate:startTime]);
}
else{
NSLog(@"image isn't downloaded, nothing to display");
}
});
});
两个同步的任务用一个异步的包起来,提交到并行队列里去,即可实现同步的方式.
3.使用分组方式
3.1 group本身是将几个有关联的任务组合起来,然后提供给开发者一个知道这个group结束的点.
虽然这个只有一个任务,但是可以利用group的结束点,去阻塞线程,从而来实现同步方式.
dispatch_group_t group = dispatch_group_create(); dispatch_queue_t queue = dispatch_get_global_queue(0, 0); NSDate *startTime = [NSDate date]; __block UIImage *image = nil; dispatch_group_async(group, queue, ^{ //1.先去网上下载图片
NSString *urlAsString = @"http://avatar.csdn.net/B/2/2/1_u010013695.jpg";
NSURL *url = [NSURL URLWithString:urlAsString]; NSError *downloadError = nil; NSData *imageData = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url] returningResponse:nil error:&downloadError]; if (downloadError == nil && imageData != nil) {
image = [[UIImage imageWithData:imageData] retain];
}
else if(downloadError != nil){
NSLog(@"error happened = %@", downloadError);
}
else{
NSLog(@"No data download");
} }); // 2.等下载好了再在刷新主线程
dispatch_group_notify(group, queue, ^{ //在主线程展示到界面里
dispatch_async(dispatch_get_main_queue(), ^{
if (image != nil) {
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
[imageView setImage:image];
[image release]; [imageView setContentMode:UIViewContentModeScaleAspectFit];
[self.view addSubview:imageView];
[imageView release]; NSDate *endTime = [NSDate date];
NSLog(@"分组同步 completed in %f time", [endTime timeIntervalSinceDate:startTime]);
}
else{
NSLog(@"image isn't downloaded, nothing to display");
}
}); }); // 释放掉
dispatch_release(group);
dispatch_group 也要手动创建和释放.
dispatch_notify()提供了一个知道group什么时候结束的点. 当然也可以使用dispatch_wait()去阻塞.
4.信号量
信号量 和 琐 的作用差不多,可以用来实现同步的方式.
但是信号量通常用在 允许几个线程同时访问一个资源,通过信号量来控制访问的线程个数.
// 信号量初始化为1
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); dispatch_queue_t queue = dispatch_get_global_queue(0, 0); NSDate *startTime = [NSDate date]; __block UIImage *image = nil; //1.先去网上下载图片
dispatch_async(queue, ^{ // wait操作-1
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // 开始下载
NSString *urlAsString = @"http://avatar.csdn.net/B/2/2/1_u010013695.jpg";
NSURL *url = [NSURL URLWithString:urlAsString]; NSError *downloadError = nil; NSData *imageData = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url] returningResponse:nil error:&downloadError]; if (downloadError == nil && imageData != nil) { image = [[UIImage imageWithData:imageData] retain];
//NSLog(@"heap %@", image);
//NSLog(@"%d",[image retainCount]);
}
else if(downloadError != nil){
NSLog(@"error happened = %@", downloadError);
}
else{
NSLog(@"No data download");
} // signal操作+1
dispatch_semaphore_signal(semaphore);
}); // 2.等下载好了再在刷新主线程
dispatch_async(dispatch_get_main_queue(), ^{ // wait操作-1
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); if (image != nil) { UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds]; [imageView setImage:image];
NSLog(@"%d",[image retainCount]);
[image release]; [imageView setContentMode:UIViewContentModeScaleAspectFit];
[self.view addSubview:imageView];
[imageView release]; NSDate *endTime = [NSDate date];
NSLog(@"信号量同步 completed in %f time", [endTime timeIntervalSinceDate:startTime]);
}
else{
NSLog(@"image isn't downloaded, nothing to display");
} // signal操作+1
dispatch_semaphore_signal(semaphore);
});
dispatch_wait会阻塞线程并且检测信号量的值,直到信号量值大于0才会开始往下执行,同时对信号量执行-1操作.
dispatch_signal则是+1操作.
二、
以上几种方式,都是通过阻塞线程的方式去实现同步。
GCD下的几种实现同步的方式的更多相关文章
- SQL 2008提供几种数据同步方式
SQL 2008提供几种数据同步的方式如下. 1.日志传送(Log Shipping),定时将主数据库的日志备份,恢复到目标数据库. 2.数据库镜像(Database Mirror),原理同日志传送, ...
- Linux 下的五种 IO 模型
概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方).操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的 ...
- Linux下多任务间通信和同步-信号
Linux下多任务间通信和同步-信号 嵌入式开发交流群280352802,欢迎加入! 1.概述 信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式.信号可以直接进行用户空间进程和内核进程之间的 ...
- Linux下多任务间通信和同步-概述
Linux下多任务间通信和同步-概述 嵌入式开发交流群280352802,欢迎加入! 在前面,我们学习了两种多任务的实现手段:进程和线程.由于进程是工作在独立的内存空间中,不同的进程间不能直接访问到对 ...
- Linux下多任务间通信和同步-消息队列
Linux下多任务间通信和同步-消息队列 嵌入式开发交流群280352802,欢迎加入! 简介 消息队列简称为队列.消息队列就是一些消息的列表.用户可以在消息队列中添加消息和读取消息等.从这点上看,消 ...
- Qt4.8在Windows下的三种编程环境搭建
Qt4.8在Windows下的三种编程环境搭建 Qt的版本是按照不同的图形系统来划分的,目前分为四个版本:Win32版,适用于Windows平台:X11版,适合于使用了X系统的各种Linux和Unix ...
- []转帖] 浅谈Linux下的五种I/O模型
浅谈Linux下的五种I/O模型 https://www.cnblogs.com/chy2055/p/5220793.html 一.关于I/O模型的引出 我们都知道,为了OS的安全性等的考虑,进程是 ...
- Linux下多任务间通信和同步-mmap共享内存
Linux下多任务间通信和同步-mmap共享内存 嵌入式开发交流群280352802,欢迎加入! 1.简介 共享内存可以说是最有用的进程间通信方式.两个不用的进程共享内存的意思是:同一块物理内存被映射 ...
- 浅谈Linux下的五种I/O模型 两篇别人的博客
http://blog.csdn.net/sinat_34990639/article/details/52778562 http://www.cnblogs.com/chy2055/p/5220 ...
随机推荐
- 初识Python第三天(二)
2.2 OrderedDict有序字典 import collections dic = collections.OrderedDict() dic['k1'] = 'v1' dic['k2'] = ...
- Tsung安装与使用
Tsung安装与使用 Tsung安装与使用的详细说明,包括测试场景的脚本配置说明 Ray 2013/11/11 目录 安装tsung Tsung运行环境安装... Tsung安装... 使用Tsu ...
- Python正则表达式学习摘要及资料
摘要 在正则表达式中,如果直接给出字符,就是精确匹配. {m,n}? 对于前一个字符重复 m 到 n 次,并且取尽可能少的情况 在字符串'aaaaaa'中,a{2,4} 会匹配 4 个 a,但 a{2 ...
- Android:Butter Knife 8.0.1配置
github地址:https://github.com/GarsonZhang/butterknife Butter Knife Field and method binding for Androi ...
- select框内容的编辑、修改、添加、删除操作
// 添加 function col_add() { var selObj = $("#mySelect"); var value="value"; var t ...
- java高薪之路__005_IO流
参考地址: 1. http://blog.csdn.net/yczz/article/details/38761237 File类 ObjectInputStream && Objec ...
- QQ授权登录
这两天在做网站第三方登录,总结一下QQ登录吧,支付宝就不用了(下载dome把ID什么的换一换就基本可以了.),本文主要说的是代码的实现方式,逻辑部分主要还是根据帮助文档来的.不懂的同学可以先看看文档. ...
- Calendar.get()方法--- WEEK_OF_YEAR 、MONTH、
1. WEEK_OF_YEAR 一年中的第几周 由于西方的一周指的是:星期日-星期六,星期日是一周的第一天,星期六是一周的最后一天, 所以,使用 calendar.get(Calendar.WEE ...
- [原创] RT7 Lite win7旗舰版精简方案
[原创] RT7 Lite win7旗舰版精简方案 墨雪SEED 发表于 2016-1-26 21:23:54 https://www.itsk.com/thread-362912-1-5.html ...
- swig之于c++
[namespace] namespace nsTest1 { int nsAdd(int a, int b) { return a + b; } } namespace nsTest2 { int ...