美文网首页
iOS线程、队列与死锁

iOS线程、队列与死锁

作者: 奔跑的徐胖子 | 来源:发表于2020-05-05 20:08 被阅读0次

    iOS中关于线程和队列,有一些概念:队列串行队列并发队列主线程主队列任务同步异步。这些概念的意义和联系又是什么呢?

    本质上

    • 队列:队列就是一个装任务的容器,存储着需要执行的各个任务。FIFO(先进先出原则)
    • 线程:线程就是具体的执行任务的人,是干活的。队列中的任务的执行要在线程中执行。一直在跑代码流。
    • 串行队列:执行里面的B任务需要等待他前面的A任务执行完毕才能执行。存放任务符合队列的本质:FIFO(先进先出)。
    • 并发队列:执行队列里面的B任务,不需要等待他前面的A任务执行完毕才能执行。存放任务符合队列的本质:FIFO。
    • 主队列:系统自动生成的,用于存放任务的队列,只有唯一的一个,他是串行队列。任务默认都存放在主队列。
    • 主线程:与主队列相关联的系统生成的用于干活的线程。任务默认都是在主线程中执行。主线程会去调度系统资源,确定是否需要开辟新的线程来干活。
    • 同步:针对当前线程的任务的代码流,当前线程如果在执行任务的过程中需要同步执行一个新的任务的时候,新任务会被立即执行,之前没有执行完的任务会停止执行,进入等待状态。形成一个阻塞。
    • 异步: 针对当前线程的任务的代码流,当前线程如果在执行任务的过程中需要异步执行一个新的任务的时候,新任务会被立即执行,但是新任务并不会阻塞当前线程。

    一、串行队列、同步执行

    向串行队列提交同步的任务的时候的执行情况:

    let s = DispatchQueue(label: "s")
    
    for i in 0..<5 {
        print("+ 添加任务:\(i)")
        s.sync {
            print("- 执行:\(i)")
            print("current: \(i), currentThread: \(Thread.current), isMainThread: \(Thread.current.isMainThread)")
            print("= 执行完毕:\(i)")
        }
    }
    
    串行队列同步任务结果

    通过结果我们知道:

    • 任务的情况:(加上了定语:在串行队列、同步的)任务。
    • 主线程的行为:不开辟新的线程在当前的主线程中执行。
    • 串行的效果:所有任务的执行都是等待上一个任务执行完毕之后再执行。
    • 同步的效果:任务的执行阻塞了当前线程(主线程)的代码流,阻断了For循环的进行,等任务执行完了才会继续For循环。

    二、串行队列、异步执行

    向串行队列提交异步任务的执行情况:

    let s = DispatchQueue(label: "s")
    
    for i in 0..<5 {
        print("+ 添加任务:\(i)")
        s.async {
            print("- 执行:\(i)")
            print("current: \(i), currentThread: \(Thread.current), isMainThread: \(Thread.current.isMainThread)")
            print("= 执行完毕:\(i)")
        }
    }
    
    串行队列异步执行结果

    通过结果我们知道:

    • 任务的情况:(加上了定语:在串行队列、异步的)任务。
    • 主线程的行为:开辟新的线程,在 同一个 新的线程中进行任务。
    • 串行的效果:所有任务的执行都是等待上一个任务执行完毕之后再执行。系统非常聪明因为是串行,所以只需要开一个线程就是依次的执行了。
    • 异步的效果:任务的执行没有阻塞当前线程(主线程)的代码流,没有阻断For循环的进行,For循环始终在执行。

    三、并发队列、同步执行

    向并发队列中提交同步任务:

    let c = DispatchQueue(label: "c", attributes: .concurrent)
    
    for i in 0..<5 {
        print("+ 添加任务:\(i)")
        c.sync {
            print("- 执行:\(i)")
            print("current: \(i), currentThread: \(Thread.current), isMainThread: \(Thread.current.isMainThread)")
            print("= 执行完毕:\(i)")
        }
    }
    
    并发队列同步执行结果

    我们可以看到,效果和上面的“一”是一样的。
    通过结果我们知道:

    • 任务的情况:(加上了定语:在并发队列、同步的)任务。
    • 主线程的行为:不开辟新的线程在当前的主线程中执行。
    • 并发的效果:由于没有开辟新的线程,同步执行又阻塞了主线程,所以,效果还是执行完一个任务,然后才开始执行下一个任务。
    • 同步的效果:任务的执行阻塞了当前线程(主线程)的代码流,阻断了For循环的进行,等任务执行完了才会继续For循环。

    四、并发队列,异步执行

    像并发队列中提交异步任务:

    let c = DispatchQueue(label: "c", attributes: .concurrent)
    
    for i in 0..<5 {
        print("+ 添加任务:\(i)")
        c.async {
            print("- 执行:\(i)")
            print("current: \(i), currentThread: \(Thread.current), isMainThread: \(Thread.current.isMainThread)")
            print("= 执行完毕:\(i)")
        }
    }
    
    并发队列异步执行结果

    通过结果我们知道:

    • 任务的情况:(加上了定语:在并发队列、异步的)任务。
    • 主线程的行为:开辟新的线程,在 不一定相同 的新的线程中进行任务。由于是并发且异步,要想实现各个任务的代码流的互不干扰不阻塞也不依赖,就需要多开辟一些线程才可以。
    • 并发的效果:任务不必等待上一个任务完成就可以开始执行。
    • 异步的效果:任务的执行没有阻塞当前线程(主线程)的代码流,没有阻断For循环的进行,For循环始终在执行。

    死锁

    通过上面的各种情况,我们就可以引申出死锁的产生原因以及状态了。那就是:
    1、当我们向一个 串行队列 中放入一个 同步执行任务A
    2、但是,这个 同步执行任务A 又包括了一个向队列中放置的 同步执行任务a
    3、两个任务是嵌套关系,A执行的时候会阻塞当前线程已有的任务,当前线程立即执行A任务
    4、但是A任务里面又包涵一个提交到队列的同步任务a
    5、这个任务a是在A之后提交的,由于在串行队列中,所以a需要等待A完成之后才能执行
    6、但是a是个同步任务,提交之后要立即阻塞并且执行。
    7、此时A的执行被a所阻塞,但是a的执行要等A执行完毕之后才能执行
    8、所以最终,A要等a执行完毕才能继续,a要等A执行完了才能开始执行
    9、这俩任务互相等待,导致当前线程永远停滞不前,就发生了死锁。

    说起来都十分拗口,但是死锁最终产生的原因就是两个任务因为阻塞相互等待的情况。这也是在使用多线程开发过程中需要十分注意的地方。

    相关文章

      网友评论

          本文标题:iOS线程、队列与死锁

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