GCD

多线程

  • 线程:线程是程序执行流的最小单元,线程是进程中的一个实体。一个进程想要还行任务,必须拥有一条线程。应用程序启动时,系统会默认开启一条线程,也就是主线程。
  • 进程:进程是一个具有一定独立功能的程序关于某次数据集合的一次运行活动,它是操作系统分配资源的基本单位。进程指在系统中正在运行的一个应用程序,就是一段程序的运行,可以理解为一个app。进程之间相互独立,运行在其专用且受保护的内存空间内,拥有独立运行的全部资源。
  • 进程与线程的关系:线程是进程的执行单元,进程的所有任务都在线程中执行。线程是CPU分配资源和调度的最小单位。一个程序可以对用多个进程,一个进程可有多个线程,但是至少要有一个线程。同一进程内的线程共享进程资源。

为什么使用多线程编程?
主线程用来描绘用户界面、处理触摸屏幕的事件等。如果在主线程中进行长时间的操作,会妨碍主线程runloop的主循环执行,从而导致不能更新用户界面,应用程序画面长时间停滞的问题。

GCDAPI

dispatch after 指定时间后执行处理

Main Dispatch Queue在主线程的runloop中执行,所以在1/60秒执行的runloop中,block最快在3秒后执行,最慢在3+1/60执行,如果在主线程中有大量处理时,时间会更长。

Dispatch Group多个处理全部结束后想执行结束处理

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, queue, ^{
        NSLog(@"blk0");
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"blk1");
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"blk2");
    });
    dispatch_group_notify(group, queue, ^{
        NSLog(@"done");
    });

dispatch_barrier_async 实现多读单写

Dispatch Semaphore 数据竞争的问题

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    /*
     * 生成 dispatch_semaphore_t
     * 初始值为1,保证可访问数组的线程同时只能为1
     */
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    NSMutableArray *arr = [NSMutableArray array];
    for (int i = 0; i < 1000; i++) {
        dispatch_async(queue, ^{
            /*
             * 等待到Dispatch Semaphore 数值大于等于1
             * 由于 Dispatch Semaphore的计数值大于等于1,所以将计数值减1
             * dispatch_semaphore_wait 执行返回
             * 此时Dispatch Semaphore 恒为0,可保证线程安全
             */
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            [arr addObject:[NSNumber numberWithInt:i]];
            /*
             * 排他处理结束,通过 dispatch_semaphore_signal函数,将数值+1
             * 如果有通过dispatch_semaphore_wait等待计数值增加的线程,优先执行
             */
            dispatch_semaphore_signal(semaphore);
        });
    }

dispatch_once 保证应用程序执行中只执行一次指定处理的API

单例的实现:线程安全

- (instancetype)shareInstance {
    static TestObject *obj = nil;
    static dispatch_once_t onceT;
    dispatch_once(&onceT, ^{
        obj = [[TestObject alloc] init];
    });
    return obj;
}

GCD的实现

通常,应用程序中编写的线程管理用的代码要在系统级实现。

  • 用户管理追加的Block的C语言层实现的FIFO队列
  • Atomi函数中实现的用于排他控制的轻量级信号
  • 用于管理线程的C语言层实现的一些容器

Dispatch Queue通过结构体和链表被实现为FIFO队列。FIFO队列管理通过dispatch_async等函数所追加的Block.Block不是直接加入到FIFO队列,而是先加Dispatch Continuation这一disptach_continuation_t类型结构体中,然后再加入到FIFO队列。Dispatch Continuation用于记忆Block所属的Dispatch Group和其他一些信息。

Dispatch Queue的执行过程

  • 当在Gloable Dispatch Queue中执行Block时,libdispatch从自身的FIFO队列中取出Dispatch Continuation,调用pthread_workqueue_additem_np函数。将改Gloable Dispatch Queue自身、符合其优先级的workqueue信息以及为执行的Dispatch Continuation 的回调函数等传参给参数。
  • pthread_workqueue_additem_np函数使用workq_kernreturn系统调用,通知workqueue增加应道执行的项目。根据该通知,XNU内核基于系统状态判断是否要生成线程。如果是Overcommit优先级的Gloable Dispatch Queue,workqueue则始终生成线程。
  • workqueue的线程执行pthread_workqueue函数,该函数调用lobdispatch的回调函数,在该回调函数中执行加入到Dispatch Continuation的Block。
  • Block执行接收后,通知Dispatch Group结束、释放等处理。开始准备执行加入到Gloable Dispatch Queue的下一个Block。

你可能感兴趣的:(GCD)