GCD基础

作者: 曼谷第一开膛手 | 来源:发表于2018-08-17 16:11 被阅读15次

    什么是多线程?

    计算机在运行一段程序的时候,会把该程序的CPU命令列配置到内存中,然后按照顺序一个一个执行命令列,这样1个CPU执行的CPU命令列为一条无分叉路径就是线程。
    而有多条这样的执行指令列的路径存在时即为多线程。
    OS实现多线程有4种方法

    • pthreads
    • NSThread
    • GCD
    • NSOperation & NSOperationQueuef
    一、Dispatch Queue和线程的关系

    什么是Dispatch Queue?

    如其名称,是执行处理的等待队列。当我们通过dispatch_async等函数把Block加入Dispatch Queue后,Dispatch Queue按照追加的顺序(FIFO)执行处理。 1293297-4e51a7482a9a6d7e.png

    Dispatch Queue的种类

    • Serial Dispatch Queue(串行队列) ——等待现在执行中处理结束再加入队列
    • Concurrent Dispatch Queue(并发队列) ——不等待现在执行中处理结束,直接加入队列 1293297-1ab53bc44e6eea1f.png
      1293297-4868cfbbcf93621c.png

    Serial Dispatch Queue

    dispatch_queue_t serial_queue = dispatch_queue_create("come.tanpei", DISPATCH_QUEUE_SERIAL);
        dispatch_async(serial_queue, ^{
            NSLog(@"block 1");
        });
        dispatch_async(serial_queue, ^{
            NSLog(@"block 2");
        });
        dispatch_async(serial_queue, ^{
            NSLog(@"block 3");
        });
        dispatch_async(serial_queue, ^{
            NSLog(@"block 4");
        });
    
    2017-09-27 11:43:40.230126+0800 aegewgr[4327:1296458] block 1
    2017-09-27 11:43:40.230335+0800 aegewgr[4327:1296458] block 2
    2017-09-27 11:43:40.230461+0800 aegewgr[4327:1296458] block 3
    2017-09-27 11:43:40.230548+0800 aegewgr[4327:1296458] block 4
    

    这里Serial Dispatch Queue只会使用一个线程,因为它是串行队列,只会当一个处理执行完了才会将下一个任务交给线程处理。

    Concurrent Dispatch Queue

    dispatch_queue_t concurrent_queue = dispatch_queue_create("come.tanpei", DISPATCH_QUEUE_CONCURRENT);
        dispatch_async(concurrent_queue, ^{
            NSLog(@"block 1");
        });
        dispatch_async(concurrent_queue, ^{
            NSLog(@"block 2");
        });
        dispatch_async(concurrent_queue, ^{
            NSLog(@"block 3");
        });
        dispatch_async(concurrent_queue, ^{
            NSLog(@"block 4");
        });
    
    2017-09-27 11:45:09.057505+0800 aegewgr[4349:1304484] block 3
    2017-09-27 11:45:09.057505+0800 aegewgr[4349:1304483] block 1
    2017-09-27 11:45:09.057522+0800 aegewgr[4349:1304486] block 4
    2017-09-27 11:45:09.057505+0800 aegewgr[4349:1304485] block 2
    

    block的执行完成
    是随机的,因为他们虽然是按顺序把任务提交给线程,但是因为不需要等待前一个任务执行,所以几乎是同时交给线程处理的。所以这里会使用多个线程,而具体线程数的多少由XNU内核决定。

    二、Dispatch Queue的使用

    1、获取队列

    在使用Dispatch Queue的时候我们可以通过dispatch_queue_create函数创建队列,也可以获取系统给我们提供的队列。系统给我们提供了两种队列 1293297-a6af209dcbce45ed.png.jpeg
    2、同步与异步
    • dispatch_async表示异步:将指定的Block”非同步“加入Dispatch Queue,不做任何等待 1293297-df4abfc994331c9c.png
    • dispatch_sync表示同步:将指定的Block”同步“的加入Dispatch Queue,在Block结束之前,dispatch_sync函数会一直等待


      1293297-97eb917212a124bc.png

      3、死锁
      由于dispatch_sync会等待Block执行结束才会继续往下执行,所以会产生死锁的情况
      我们直接在主线程中同步加入一个Blcok:

    dispatch_queue_t main_queue = dispatch_get_main_queue();
        dispatch_sync(main_queue, ^{
            NSLog(@"main queue");
        });
        NSLog(@"go on");
    

    无任何输出,程序直接卡死了。这就是造成了死锁。
    因为该源代码在main_queue(主线程)中加入一个加入一个指定的Block,并等待其执行结束。而由于main_queue是一个串行队列,它要等当前线程中的任务处理完后才会把队列中的任务提交到主线程,而主线程又在等待这段代码执行,所以造成了相互等待,就产生了死锁。(而并发队列不会产生死锁)

    dispatch_queue_t global_queue = dispatch_get_global_queue(0, DISPATCH_QUEUE_PRIORITY_DEFAULT);
        dispatch_sync(global_queue, ^{
            NSLog(@"global_queue out");
            dispatch_sync(global_queue, ^{
                NSLog(@"global_queue in");
            });
        });
    
    2017-09-27 16:11:56.332317+0800 aegewgr[4723:1590202] global_queue out
    2017-09-27 16:11:56.332446+0800 aegewgr[4723:1590202] global_queue in
    

    所以产生死锁的话一般都是在串行队列中并且是在一个线程中同步往这个线程提交一个Block。

    相关文章

      网友评论

          本文标题:GCD基础

          本文链接:https://www.haomeiwen.com/subject/drkobftx.html