zoukankan      html  css  js  c++  java
  • GCD与多线程

    GCD与多线程

     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释放。比如下面两段代码分别创建串行队列和并行队列:

          1. dispatch_queue_t serialQ = dispatch_queue_create("eg.gcd.SerialQueue", DISPATCH_QUEUE_SERIAL);  
          2. dispatch_async(serialQ, ^{  
          3.     // Code here  
          4. });  
          5. dispatch_release(serialQ);  
          6.   
          7. dispatch_queue_t concurrentQ = dispatch_queue_create("eg.gcd.ConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);  
          8. dispatch_async(concurrentQ, ^{  
          9.     // Code here  
          10. });  
          11. dispatch_release(concurrentQ);  
           而系统默认就有一个串行队列main_queue和并行队列global_queue:

           

          [cpp] view plaincopy
           
           
          1. dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  
          2. dispatch_queue_t mainQ = dispatch_get_main_queue();  

               通常,我们可以在global_queue中做一些long-running的任务,完成后在main_queue中更新UI,避免UI阻塞,无法响应用户操作:
          [cpp] view plaincopy
           
           
          1. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
          2.     // long-running task  
          3.     dispatch_async(dispatch_get_main_queue(), ^{  
          4.         // update UI  
          5.     });  
          6. });  
               上面提到dispatch_async这个接口,用来提交blcok给指定queue进行异步执行。这个接口会在成功提交block后立即返回,然后继续执行下去。由于block是定义在栈上的,所以需要将其复制到堆上,见这里

               与之相对应的是dispatch_sync接口,提交block以供同步执行。这个接口会等到block执行结束才返回,所以不需要复制block。So,如果在调用该接口在当前queue上指派任务,就会导致deadlock。维基百科上给了段示例代码:

           

          [cpp] view plaincopy
           
           
          1. dispatch_queue_t exampleQueue = dispatch_queue_create("com.example.unique.identifier", NULL );  
          2. dispatch_sync( exampleQueue,^{  
          3.   dispatch_sync( exampleQueue,^{  
          4.     printf("I am now deadlocked... ");  
          5.   });});  
          6. dispatch_release( exampleQueue );  
               如果追求的是并发,那么dispatch_sync有什么用呢?关于dispatch_sync的用途,StackOverFlow是这样讨论的:

          Can anyone explain with really clear use cases what the purpose of dispatch_sync in GCD 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 queue q. 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 available
          dispatch_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中:

           

          1. -(void)viewDidAppear:(BOOL)animated{  
          2.   
          3.   
          4.     dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  
          5.     dispatch_async(concurrentQueue, ^{  
          6.         __block UIImage *image = nil;  
          7.         dispatch_sync(concurrentQueue, ^{  
          8.             /* 下载图片 */  
          9.              
          10.             NSString *urlAsString = @"http://images.apple.com/mac/home/images/promo_lead_macbook_air.jpg";  
          11.            NSURL *url = [NSURL URLWithString:urlAsString];  
          12.             NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];  
          13.             NSError *downloadError = nil;  
          14.             NSData *imageData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:&downloadError];  
          15.             if (downloadError == nil && imageData != nil){  
          16.                image = [UIImage imageWithData:imageData];  
          17.             } else if(downloadError!=nil){  
          18.                 NSLog(@"Error happened = %@", downloadError);  
          19.             }else {  
          20.                 NSLog(@"No data could get downloaded from the URL.");  
          21.             }  
          22.         });  
          23.         //在主队列中把图片展示给用户  
          24.         dispatch_sync(dispatch_get_main_queue(), ^{  
          25.               
          26.             if (image != nil){  
          27.                 /* 创建一个UIImageView */  
          28.                 UIImageView *imageView = [[UIImageView alloc]  
          29.                                           initWithFrame:self.view.bounds];  
          30.                 /* 设置图片*/  
          31.                 [imageView setImage:image];  
          32.                 /* 设置图片比例*/  
          33.                 [imageView setContentMode:UIViewContentModeScaleAspectFit];  
          34.                 /* 添加视图 */  
          35.                 [self.view addSubview:imageView];  
          36.             } else {  
          37.                 NSLog(@"Image isn't downloaded. Nothing to display.");  
          38.             } });  
          39.      });   
          40.   
          41. }  


          运行结果:

           

  • 相关阅读:
    Session共享的解决方案
    用IIS配置反向代理
    authorization配置
    git之https或http方式设置记住用户名和密码的方法
    微信分享接口
    为你的Visual Studio单独设置代理服务器
    HTTP错误404.13
    MVC5的AuthorizeAttribute详解
    【MVC5】画面多按钮提交
    PetaPoco dynamic
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3290391.html
Copyright © 2011-2022 走看看