OS学习之路八(GCD与多线程)
来源:互联网 发布:奶牛养殖软件 编辑:程序博客网 时间:2024/06/05 16:39
GCD,全称Grand Central Dispath,是苹果开发的一种支持并行操作的机制。它的主要部件是一个FIFO队列和一个线程池,前者用来添加任务,后者用来执行任务。
GCD中的FIFO队列称为dispatch queue,它可以保证先进来的任务先得到执行(但不保证一定先执行结束)。
通过与线程池的配合,dispatch queue分为下面两种:
- Serial Dispatch Queue -- 线程池只提供一个线程用来执行任务,所以后一个任务必须等到前一个任务执行结束才能开始。
- Concurrent Dispatch Queue -- 线程池提供多个线程来执行任务,所以可以按序启动多个任务并发执行。
1. Basic Management
我们可以通过dispatch_queue_cretae来创建队列,然后用dispatch_release释放。比如下面两段代码分别创建串行队列和并行队列:
dispatch_queue_t serialQ = dispatch_queue_create("eg.gcd.SerialQueue", DISPATCH_QUEUE_SERIAL);dispatch_async(serialQ, ^{ // Code here});dispatch_release(serialQ);dispatch_queue_t concurrentQ = dispatch_queue_create("eg.gcd.ConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);dispatch_async(concurrentQ, ^{ // Code here});dispatch_release(concurrentQ);
- dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- dispatch_queue_t mainQ = dispatch_get_main_queue();
通常,我们可以在global_queue中做一些long-running的任务,完成后在main_queue中更新UI,避免UI阻塞,无法响应用户操作:dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // long-running task dispatch_async(dispatch_get_main_queue(), ^{ // update UI }); });
与之相对应的是dispatch_sync接口,提交block以供同步执行。这个接口会等到block执行结束才返回,所以不需要复制block。So,如果在调用该接口在当前queue上指派任务,就会导致deadlock。维基百科上给了段示例代码:
dispatch_queue_t exampleQueue = dispatch_queue_create("com.example.unique.identifier", NULL ); dispatch_sync( exampleQueue,^{ dispatch_sync( exampleQueue,^{ printf("I am now deadlocked...\n"); });}); dispatch_release( exampleQueue );
如果追求的是并发,那么dispatch_sync有什么用呢?关于dispatch_sync的用途,StackOverFlow是这样讨论的:Can anyone explain with really clear use cases what the purpose of
dispatch_sync
inGCD
is for? I can't understand where and why I would have to use this.高手回答:
You use it when you want to execute a block and wait for the results.
One example of this is the pattern where you're using a dispatch queue instead of locks for synchronization. For example, assume you have a shared NSMutableArray
a
, with access mediated by dispatch queueq
. A background thread might be appending to the array (async), while your foreground thread is pulling the first item off (synchronously): NSMutableArray *a = [[NSMutableArray alloc] init];// All access to `a` is via this dispatch queue!dispatch_queue_t q = dispatch_queue_create("com.foo.samplequeue", NULL);dispatch_async(q, ^{ [a addObject:something]; }); // append to array, non-blocking__block Something *first = nil; // "__block" to make results from block availabledispatch_sync(q, ^{ // note that these 3 statements... if ([a count] > 0) { // ...are all executed together... first = [a objectAtIndex:0]; // ...as part of a single block... [a removeObjectAtIndex:0]; // ...to ensure consistent results }});
下面附上一个Demo :(后台队列下载图片,当下载完后,调用主线程在前台显示)
在Concoller中:
-(void)viewDidAppear:(BOOL)animated{ dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(concurrentQueue, ^{ __block UIImage *image = nil; dispatch_sync(concurrentQueue, ^{ /* 下载图片 */ NSString *urlAsString = @"http://images.apple.com/mac/home/images/promo_lead_macbook_air.jpg"; NSURL *url = [NSURL URLWithString:urlAsString]; NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url]; NSError *downloadError = nil; NSData *imageData = [NSURLConnection sendSynchronousRequest:urlRequest 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 could get downloaded from the URL."); } }); //在主队列中把图片展示给用户 dispatch_sync(dispatch_get_main_queue(), ^{ if (image != nil){ /* 创建一个UIImageView */ UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds]; /* 设置图片*/ [imageView setImage:image]; /* 设置图片比例*/ [imageView setContentMode:UIViewContentModeScaleAspectFit]; /* 添加视图 */ [self.view addSubview:imageView]; } else { NSLog(@"Image isn't downloaded. Nothing to display."); } }); }); }
运行结果:
- OS学习之路八(GCD与多线程)
- IOS学习之路八(GCD与多线程)
- IOS学习之路八(GCD与多线程)
- GCD 学习(八)dispatch_semaphore
- GCD 学习(八)dispatch_semaphore
- iOS多线程学习之GCD
- iOS 多线程学习之GCD
- iOS多线程之GCD学习
- 【Mac OS X/iOS多线程编程】GCD用法学习笔记
- iOS与OS多线程和内存管理----GCD底层实现
- 多线程之GCD(一)
- 多线程之GCD(1)
- 多线程之GCD(2)
- 多线程之GCD(3)
- ios多线程学习之GCD线程锁
- [iOS学习]多线程之NSOperation和GCD
- iOS多线程学习之GCD详解
- 拾遗系列(八)多线程(NSThread、GCD、NSOperation)
- [20130829]A Short History of Nearly Everything[serial]
- _RecordsetPtr
- hdu4685
- linux 上层应用 获取网卡工作模式 方法
- AES加密算法(C++实现,附源码)
- OS学习之路八(GCD与多线程)
- Linux常用命令
- linux 进程通信几种方式优缺点
- 给定一个字符串,仅由a,b,c 3种小写字母组成。
- 定义为volatile的变量有什么作用
- ORACLE中like与instr性能大比拼
- 密码学基础
- UVaOJ 11038 How Many O's?
- 如何安全的存储密码