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下的几种实现同步的方式的更多相关文章

  1. SQL 2008提供几种数据同步方式

    SQL 2008提供几种数据同步的方式如下. 1.日志传送(Log Shipping),定时将主数据库的日志备份,恢复到目标数据库. 2.数据库镜像(Database Mirror),原理同日志传送, ...

  2. Linux 下的五种 IO 模型

    概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方).操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的 ...

  3. Linux下多任务间通信和同步-信号

    Linux下多任务间通信和同步-信号 嵌入式开发交流群280352802,欢迎加入! 1.概述 信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式.信号可以直接进行用户空间进程和内核进程之间的 ...

  4. Linux下多任务间通信和同步-概述

    Linux下多任务间通信和同步-概述 嵌入式开发交流群280352802,欢迎加入! 在前面,我们学习了两种多任务的实现手段:进程和线程.由于进程是工作在独立的内存空间中,不同的进程间不能直接访问到对 ...

  5. Linux下多任务间通信和同步-消息队列

    Linux下多任务间通信和同步-消息队列 嵌入式开发交流群280352802,欢迎加入! 简介 消息队列简称为队列.消息队列就是一些消息的列表.用户可以在消息队列中添加消息和读取消息等.从这点上看,消 ...

  6. Qt4.8在Windows下的三种编程环境搭建

    Qt4.8在Windows下的三种编程环境搭建 Qt的版本是按照不同的图形系统来划分的,目前分为四个版本:Win32版,适用于Windows平台:X11版,适合于使用了X系统的各种Linux和Unix ...

  7. []转帖] 浅谈Linux下的五种I/O模型

    浅谈Linux下的五种I/O模型 https://www.cnblogs.com/chy2055/p/5220793.html  一.关于I/O模型的引出 我们都知道,为了OS的安全性等的考虑,进程是 ...

  8. Linux下多任务间通信和同步-mmap共享内存

    Linux下多任务间通信和同步-mmap共享内存 嵌入式开发交流群280352802,欢迎加入! 1.简介 共享内存可以说是最有用的进程间通信方式.两个不用的进程共享内存的意思是:同一块物理内存被映射 ...

  9. 浅谈Linux下的五种I/O模型 两篇别人的博客

     http://blog.csdn.net/sinat_34990639/article/details/52778562  http://www.cnblogs.com/chy2055/p/5220 ...

随机推荐

  1. python开发进阶之路(一)

    哎!好久没有写博客了,怪想念的,今天听了偶像的讲解,好多以前感觉很模糊的概念今天一下子就明朗了.下面就来整理一下今天的收获 一.如何成为一名优秀的开发人员 1.1  得先对自己使用的开发语言了如指掌, ...

  2. wf(四)

    我们已经在c#和xaml上编写了工作流,或者有的人会觉得在xaml上编写的workflow没什么优点,然而其实xaml其实具有一些很特别的优势. 1. xaml支持工作流设计器,c#不支持: 2. x ...

  3. Temporary ASP.NET 拒绝访问

    CS0016: 未能写入输出文件“c:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\root\dd813f66 ...

  4. python学习之字典

    1.字典 列表存储的数据比较单一也不够灵活,这时我们可以使用字典来存储某些多内容的数据,字典是无顺序的 1.简单的字典 book={ 'huqiang':13457412571, 'Jasper':1 ...

  5. 基于Node的PetShop,oauth2认证RESTful API

    前篇 - 基本认证,用户名密码 后篇 - OAuth2 认证 前文使用包passport实现了一个简单的用户名.密码认证.本文改用oauth2来实现更加安全的认证.全部代码在这里. OAUTH2 用户 ...

  6. R之data.table -melt/dcast(数据合并和拆分)

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 30.0px "Helvetica Neue"; color: #323333 } p. ...

  7. Java精确计算小数

    Java在计算浮点数的时候,由于二进制无法精确表示0.1的值(就好比十进制无法精确表示1/3一样),所以一般会对小数格式化处理. 但是如果涉及到金钱的项目,一点点误差都不能有,必须使用精确运算的时候, ...

  8. golang获取数据表转换为json通用方法

    package main import ( "database/sql" "fmt" "log" "net/http" ...

  9. git: No refs in common and none specified; doing no

    用gitolite新建项目,clone后首次push,可能会出现:     $ git push No refs in common and none specified; doing nothing ...

  10. absolute和fixed

    共同点: 改变行内元素的呈现方式,display设置为block:让元素脱离文档流,不占据空间:默认会覆盖到非定位元素上. 不同点: absolute的根元素是相对于static定位以外的第一个父元素 ...