zoukankan      html  css  js  c++  java
  • GCD之各种派发

    dispatch_apply的用法

    并行模拟for循环,将指定的代码循环10次,一般会把这些代码附加到一个queue上,然后在 dispatch_apply里并行

    dispatch_queue_t queue = dispatch_get_globel_queue(DISPATCH_QUEUE_PREORITY_DEFAULT,0)

    dispatch_apply(10, queue, ^(size_t index){

      NSLog("并行执行--%@",index);

    });

    dispatch_apply_f的用法

    dispatch_apply 和 dispatch_apply_f 是同步函数,会阻塞当前线程直到所有循环迭代执行完成。当提交到并发queue时,循环迭代的执行顺序是不确定的 

    dispatch_after

    延迟指定时间之后执行任务

    dispatch_after(dispatch_time_t when, dispatch_queue_t queue, ^(void)block)

     

    when:延迟执行时间 一般是一个这样的时间函数: dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC))

    queue:队列 dispatch_get_main_queue()或者 dispatch_get_global_queue()

    block:执行的任务

    dispatch_once

    dispatch_once(dispatch_once_t *predicate, ^(void)block)

    predicate: 用来判断需要执行的任务是否执行完成

    block :需要执行的一次性任务

    + (instantClass *)sharedClient {

      static instantClass *_sharedClient = nil;

      static dispatch_once_t onceToken;

      dispatch_once(&onceToken, ^{

         _sharedClient = [[instantClass alloc] init];

      });

       return _sharedClient;

    }

     dispatch_group

    dispatch_grpup,把若干个任务放到一个dispatch group中

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PREORITY_DEFAULT,0);

    dispatch_queue_group group = dispatch_group_craete();

    dispatch_group_aysnc(group, queue,^{

      //do some async work

    });

    dispatch_group_async 和 dispatch_async一样,会把任务放到queue中执行,只不过它比dispatch_async多了一步操作,就是把这个任务和group相关联,

    把这些任务放到group之后,我们可以调用dispatch_group_wait来等待任务完成。若任务已经全部完成或者为空,直接返回,否则等待所有任务完成之后返回。注意返回之后任务清空。

    dispatch_group_wait(group,DISPATCH_TIME_FORVER);

    dispatch_release(group);

    dispatch_semaphore信号量

    GCD信号量机制

    信号量就是一些有限可数的资源。比如打印机,假如系统有两台打印机。但同时又5个任务要使用打印机,那么只有2个任务能同时进行打印,剩下3个要等待着2个任务打印完。那么程序工作过程应该是:任务首先获取打印机资源(dispatch_semaphore_wait),如果没有打印机可用了就要等待,直到其他任务用完这个打印机。当任务获取到打印机,就开始执行打印任务。任务用完打印机工作后,就必须把占用打印机释放(dispatch_semaphore_signal),以便其他任务可以接着打印。

    //创建资源的信号量,只创建一次,比如2台打印机,那么 RESOURCE_SIZE为2.

    dispatch_semaphore_t sema = dispatch_semaphore_create(RESORCE_SIZE);

    //如果任务使用一个资源时,使用前调用dispatch_semaphore_wait,用完后dispatch_semaphore_signal.

    //下面的代码可能在多个线程中调用多次

    dispathc_semaphore_wait(sema, DISPATCH_TIME_FORVER);

    //do some work here , the work will use one resource.

    dispatch_semaphore_signal(sema);

    信号量必须在资源使用之前调用dispatch_semaphore_create创建,而且只创建一次,RESOURCE_SIZE是可用资源总数。使用资源时dispatch_semaphore_wait将资源的可用数减少一个,如果当前没有可用资源了,将会等待直到其他线程回收资源,即调用dispatch_semaphore_signal让可用资源增加。用完资源后调用dispatch_semaphore_signal回收可利用资源。资源可用数将增加一个。

    如果是生产者-消费者模型的花,RESOURCE_SIZE可能最初为0,那么生产者调用dispatch_semaphore_signal来生产一个单位的资源,消费者调用dispatch_semaphore_wait来消费(减少)一个单位的资源。当资源不足时,消费者会一直等待到资源数大于0,即生产者生成新的资源。

    dispatch source(定时器,进程,文件,Mach port相关)

    dispatch source 是GCD中监听一些系统事件的,有个Dispatch对象,它包括定时器、文件监听、进程监听,Mach port 监听等类型。

    可以通过dispatch_source_create创建一个Dispatch Source:

    dispatch_source_t dispatch_source_cerate(

      dispatch_source_type_t type,

      uintptr_t handle, 

      unsigned long mask,

      dispatch_queue_t queue);

    这里可以指定Dispatch Source 的类型, type可以为文件读或写、进程监听等。handel为监听对象的句柄,如果是文件就是文件描述符,如果是进程就是进程ID, mask用来指定一些想要监听的时间,它的意义取决于type.queue指定事件处理的任务队列。

    创建好dispatch source 之后,我们要为 dispatch source 设置一个事件处理模块。可以用dispatch_source_set_event_handler或者dispatch_source_set_event_hander_f来设置:

    void dispatch_source_source_set_event_handler(

      dispatch_source_t source,

      dispatch_block_t handler

    )

    设置好Dispatch Source 后就可以调用dispatch_resume来启动监听。

    如果相应的事件发生就会触发事件处理模块。

    同时我么也可以设置一个取消处理模块:

    dispatch_source_set_cancel_handler(mySource, ^{

      //Close a file descriptor opened earlier.

      close(fd);

    });

    取消处理模块会在Dispatch Source 取消时调用。

    定时器

    定时器 Dispatch Source 可以每隔一个固定的时间处理一下任务。

    dispatch_source_t CreateDispatchTimer(uint64_t interval, uint64 leeway, dispatch_queue_t queue, dispatch_block_t block){

      dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0 , queue);

      if(timer){

        dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval, leeway);

        dispatch_source_set_event_handler(timer, block);

        dispatch_resume(timer);

      }

      return timer;

    }

    void MyCreateTimer(){

      dispatch_source_t aTimer = CreateDispatchTimer(30ull * NSEC_PER_SEC,1ull * NSEC_PER_SEC, dispatch_get_main_queue(), ^{ MyPeriodicTask();})

    //Store it somewhere for later use

      if(aTimer){

        MyStoreTimer(aTimer);

      }

    }

     监听文件事件

    监听文件事件分好几个类型,有读、写、属性的监听

    读取文件

    dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd ,0, queue);

    dispatch_source_set_event_handler(source, ^{

      //get some data form the source variable, which is captured

      //form the parent context.

      size_t estimated = dispatch_source_get_data(source);

      //continue reading the descriptor

    });

    dispatch_resume(source);

    写文件

    dispatch_source_t writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0 , queue);

    if(!writeSource){

      close(fd);

      return NULL;

    }

    dispatch_source_set_event_handeler(writeSource, ^{

      size_t bufferSize = MyGetDataSize();

      void *buffer = malloc(bufferSize);

      size_t actual = MyGetData(buffer, bufferSize);

      write(fd, buffer, actual);

      

      free(buffer);

      

      //cancel and release the dispatch source when done.

      dispatch_source_cancel(writeSource);

    });

    监听文件属性

    dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_RENAME, QUEUE);

    if(source){

      //copy the filename for ater use

      int length = strlen(filename);

      char * newString = (char*) malloc(length + 1);

      new String = strcpy(newString , filename);

      dispatch_set_context(source, newString);

      

      //install the event handler to process the name change dispatch_source_set_event_handeler(source, ^{

        const char* oldFilename = (char*)dispatch_get_context(source);

        MyUpdateFileName(oldFilename, fd);

      });

      //Install a cancellation handler to free the descriptor

      //and the stored string

      dispatch_source_set_cancel_hander(source, ^{

        char *fileStr = (char*)dispatch_get_context(source);

        free(fileStr);

        close(fd);

      });

      

      // Start processing events.

      dispatch_resume(source);

    }else{

      close(fd);

    }

    监听进程事件

    DISPATCH_PROC_EXIT是一个监听进程退出的类型。

    dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, parentPID, DISPATCH_PROC_EXIT, queue);

    if(source){

      dispatch_source_set_event_handler(source, ^{

        MySetAppExitFlag();

        dispatch_source_cancel(source);

        dispatch_rellease(source);

      });

      dispach_resume(source);

    }

    监听中断信号

    dispatch_source_t source = dispatch_create_source(DISPATCH_SOURCE_TYPE_SIGNAL, SIGHUP, 0, queue);

    if(source){

      dispatch_source_set_event_handler(source, ^{

        MyProcessSIGHUP();

      });

    //Start processing signals

    dispatch_requme(source);

    }

    
    
  • 相关阅读:
    WebStorm 使用过程中出现的一些问题以及解决方案
    常用软件工具收集
    个人博客运营策略总结
    OpenGL glMatrixMode() 函数解释与例子
    让搭建在 Github Pages 上的 Hexo 博客可以被 Google 搜索到
    使用 statcounter 统计 Hexo 博客访问量
    使用 Hexo,Material Theme 以及 Github Pages 搭建个人博客
    Ubuntu 16.04下配置 Nginx 与 Node.js 以及服务的部署
    一个简单的在线代码编辑器的实现
    在已有 Windows10 系统的基础上,安装 Ubuntu17.10 系统(新版 BIOS)
  • 原文地址:https://www.cnblogs.com/wjw-blog/p/7799295.html
Copyright © 2011-2022 走看看