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. 给jar包进行数字签名(2014-06-28记)

    整理一下两年前用到的一些资料. 为了使Applet或者Java Web Start程序能够访问客户端本地资源,需要对Applet或者JWS程序jar包进行数据签名,当客户端打开Applet或者JWS程 ...

  2. Ugly Number

    public class Solution { public bool IsUgly(int num) { ) return false; ) return true; *==num){ num = ...

  3. mysql常用命令(3)

    一.启动与关闭 1.1 Linux下启动mysql 的命令: a. rpm包安装:service mysqld start b. 源码包安装:/usr/local/mysql/bin/mysqld_s ...

  4. [转] 停止支持的老版本ubuntu源列表-old-releases

    我使用的是ubuntu 9.10,在网上找了大半个月之后,今天终于找到了可用的源地址.感谢这位cgjcgs仁兄. 点击阅读原文 ubuntu的普通版本支持的时间都有限,过了支持的时间,更新源都会被停用 ...

  5. js页面刷新之实现框架内外刷新(整体、局部)

    这次总结的是框架刷新: 框架内外的按钮均可以定义网页重定向, 框架内部页面的按钮可以实现局部刷新, 框架外部页面的按钮可以实现整页刷新. 代码如下(两个html页面): <!--主界面index ...

  6. [SDN] What is SDN?

    本篇学习笔记写于 Sun Nov 13 15:08:02 2016, 可能有认识不全面的地方. 参考资料为ONF的官方网站中: Software-Defined Networking (SDN) De ...

  7. 红字差评系列1.第K小数

    [题目分析] 二分答案?smg,我太弱了 //不开longlong wa到挺了 #include <cstdio> #include <cstring> #include &l ...

  8. 数据库连接池配置 - Oracle,SQL Server,DB2,MYSQL,SQLLITE3

    ################## 数据库连接配置 ################## #Oracle#hibernate.connection.driverClass=oracle.jdbc.d ...

  9. Linux -- 文件统计常用命令

    标签(空格分隔): Linux sort -- 文件内排序命令 sort将文件的每一行作为一个单位,相互比较,比较原则是从首字符向后,依次比较其ASCII码. 按每行升序排序: sort seq.tx ...

  10. IOS开发数据库篇—SQLite模糊查询

    IOS开发数据库篇—SQLite模糊查询 一.示例 说明:本文简单示例了SQLite的模糊查询 1.新建一个继承自NSObject的模型 该类中的代码: // // YYPerson.h // 03- ...