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 ...
随机推荐
- 五、Standard Controllers
1.standardController:标准的controller 是同页面的standard Object的界面button的功能和逻辑是一样的<apex:page standardCont ...
- java中如何获取昨天的当前日期
在java里,获取昨天的当前日期,可以采用calendar来做,也可以采用date来做:如下: 1.采用calendar来做: Calendar cal=Calendar.getInstance(); ...
- [转]Setup-Subversion-1.6.5+TortoiseSVN-v1.6.5
转载地址:http://xietingfengsxm.blog.163.com/blog/static/994118512010729111624385/ 开发环境: myEclipse6.5+ecl ...
- Intellij IDEA 快捷键介绍
ctrl-w 使所选表达式逐步增大直到选取整个文件 ctrl+shft+w 逐步减少选中 ctrl-n 可以通过键入类名查找一个类 ctrl-shift-n 可以查找文件 ctrl-e 得到 ...
- 四大开源协议比较:BSD、Apache、GPL、LGPL (转)
转自:http://www.lupaworld.com/portal.php?mod=view&aid=205552&page=all 本文参考文献:http://www.fsf.or ...
- sourceforge免费空间申请及使用笔记
sourceforge免费空间申请及使用笔记 sourceforge免费空间安装WordPress博客程序 WordPress博客程序安装文件的上传需要使用工具WinSCP. 你需要在FTP地址填写的 ...
- hbm配置文件 generator节点各种解释
今天犯了个错误 generator节点class属性有这么几个值(主键生成策略方案): assigned:由用户指定主键值 sequence:由oracle序列生成 increment:对类型为lon ...
- JavaScript的一点自我总结
学习前端不知不觉都两个月了,从零基础到现在,网页布局没多大问题,就是JS学的很差,有一段时间都怀疑自己是不是选错了.但自我调节后,心态发生了一些变化后,学习也没那么痛苦了.虽然做不到看代码像看初恋那样 ...
- [css] 页面重构“鑫三无准则” 之“无宽度”准则
原创文章,转载请注明来自张鑫旭-鑫空间-鑫生活[http://www.zhangxinxu.com]本文地址:http://www.zhangxinxu.com/wordpress/?p=1152 一 ...
- kafka集群zookeeper集群详细配置
http://www.cnblogs.com/luotianshuai/p/5206662.html