美文网首页
iOS 多线程 基本概念

iOS 多线程 基本概念

作者: 咖啡豆8888 | 来源:发表于2018-11-29 16:22 被阅读35次

    前言

    GCD源码地址
    GNUStep
    (是GNU计划项目之一,他将cocoa库重新开源实现了一遍,不是apple官方文档,但是具有一定的参考价值)
    常见的多线程方案一般分为这几种

    线程方案

    GCD函数

    //异步执行任务
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
            
        });
    //同步执行任务
    dispatch_sync(dispatch_get_global_queue(0, 0), ^{
            
        });
    

    同步 异步 串行 并发

    • 同步、异步主要影响:能不能开启新线程。
    • 串行、并发主要影响:任务执行方式,串行一个任务执行完毕之后,在执行下一个。并发多个任务同时执行。

    死锁问题

    先看一段代码

    - (void)viewDidLoad {
        [super viewDidLoad];
         NSLog(@"任务1");
        dispatch_sync(dispatch_get_main_queue(), ^{
             NSLog(@"任务2");
        });   
         NSLog(@"任务3");
    }
    

    上面一段代码发生了死锁,为什么呢?原因就是:viewDidLoad是在主队列里面执行的,当执行到任务2的时候,因为是同步任务,所以需要立刻执行任务2,但是队列是先进先出的概念,viewDidLoad本身也是一个任务,他需要执行完任务3之后才能执行任务2,但是任务2需要立即执行,也就是说任务3等待任务2执行完毕执行,任务2有等待任务3执行完毕执行,造成了死锁,程序卡死在任务2处。
    死锁原理:使用sync函数往当前串行队列(serial quque)添加任务就会产生死锁

    [self performSelector:@selector(test) withObject:nil afterDelay:.0]; 延迟方法

    - (void)viewDidLoad {
        [super viewDidLoad];
        dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
        dispatch_async(queue, ^{
            NSLog(@"1");
            [self performSelector:@selector(test) withObject:nil afterDelay:.0];
            NSLog(@"3");
        });
    }
    - (void)test {
        NSLog(@"2");
    }
    ---------------------------------------------------
    2018-11-29 14:09:46.184533+0800 demodemo[88317:5593889] 1
    2018-11-29 14:09:46.185962+0800 demodemo[88317:5593889] 3
    

    延迟方法的底层实现是在runloop内部添加定时器来处理任务的,但是子线程默认是没有启动RunLoop的,所以导致方法失效。

    dispatch_async(queue, ^{
            NSLog(@"1");
            [self performSelector:@selector(test) withObject:nil afterDelay:.0];
            NSLog(@"3");
            [[NSRunLoop currentRunLoop]addPort:[NSPort new] forMode:NSDefaultRunLoopMode];
            [[NSRunLoop currentRunLoop]runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        });
    ---------------------------------------------------
    2018-11-29 14:20:43.557833+0800 demodemo[88643:5608216] 1
    2018-11-29 14:20:43.559215+0800 demodemo[88643:5608216] 3
    2018-11-29 14:20:43.559472+0800 demodemo[88643:5608216] 2
    

    启动RunLoop,可以执行延迟函数,因为是延迟函数,需要等待下一次被唤醒的时候处理定时器任务,所以3先被执行。

    [self performSelector:@selector(test) withObject:nil] 方法的底层原理是[class msgSend],跟延迟方法是不同的。

    从GNUStep可以大致推出延迟方法apple的源码实现是这样的

    - (void) performSelector: (SEL)aSelector
              withObject: (id)argument
              afterDelay: (NSTimeInterval)seconds
    {
      NSRunLoop     *loop = [NSRunLoop currentRunLoop];
      GSTimedPerformer  *item;
    
      item = [[GSTimedPerformer alloc] initWithSelector: aSelector
                             target: self
                           argument: argument
                              delay: seconds];
      [[loop _timedPerformers] addObject: item];
      RELEASE(item);
      [loop addTimer: item->timer forMode: NSDefaultRunLoopMode];
    }
    

    队列组

    dispatch_group_t group = dispatch_group_create();
        dispatch_queue_t queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_CONCURRENT);
        dispatch_group_async(group, queue, ^{
            for (int i = 0; i<5; i++) {
                NSLog(@"任务1");
            }
        });
        dispatch_group_async(group, queue, ^{
            for (int i = 0; i<5; i++) {
                NSLog(@"任务2");
            }
        });
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"完成");
        });
    ---------------------------------------------
    2018-11-29 15:30:19.442732+0800 demodemo[90541:5689534] 任务2
    2018-11-29 15:30:19.442732+0800 demodemo[90541:5689182] 任务1
    2018-11-29 15:30:19.443865+0800 demodemo[90541:5689182] 任务1
    2018-11-29 15:30:19.443865+0800 demodemo[90541:5689534] 任务2
    2018-11-29 15:30:19.444347+0800 demodemo[90541:5689182] 任务1
    2018-11-29 15:30:19.444362+0800 demodemo[90541:5689534] 任务2
    2018-11-29 15:30:19.444449+0800 demodemo[90541:5689182] 任务1
    2018-11-29 15:30:19.444501+0800 demodemo[90541:5689534] 任务2
    2018-11-29 15:30:19.444640+0800 demodemo[90541:5689182] 任务1
    2018-11-29 15:30:19.445137+0800 demodemo[90541:5689534] 任务2
    2018-11-29 15:30:19.446057+0800 demodemo[90541:5689084] 完成
    

    相关文章

      网友评论

          本文标题:iOS 多线程 基本概念

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