b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

五种情况让您了解GCD僵局

电脑杂谈  发布时间:2020-05-30 22:24:05  来源:网络整理

死锁举例_死锁_ccriticalsection 多线程 死锁

作者:brighttj(@saitjr
网址:http://www.brighttj.com/ios/ios-gcd-deadlock.html

死锁一直是使用多线程时需要注意的问题. 以前,只有模糊的同步,异步,串行和并行概念. 现在也该进行梳理了. 回顾以前的博客,很久以来一直没有干货(好像以前有干货),所以我尽力了这个博客,并且还从其他博客中借用了很多例子来解释GCD死锁问题.

环境信息:

Mac OS X 10.10.5

Xcode 6.4

iOS 8.4

使用GCD时,我们会将要处理的任务放入块中,然后将任务附加到相应的队列中. 此队列称为调度队列. 但是,分派队列有两种类型,一种是等待上一次执行完成,然后执行下一个串行分派队列,称为串行队列. 下一个并发调度队列称为并行队列. 它们都遵循FIFO原则.

举一个简单的例子,在三个任务中输出1、2、3,串行队列输出是有序的1、2、3,但是并行队列的先后顺序就不一定了。

那么,如何执行并行队列?

尽管可以同时处理多个任务,但是并行队列处理量取决于当前系统状态. 如果当前系统状态最多处理2个任务,则将1、2排在首位,当操作3时死锁举例,则取决于谁完成1或2,然后是3.

这里简要介绍了串行和并行,实际上有许多技术要点,您可以自己理解.

串行和并行用于队列,而同步和异步用于线程. 最大的区别是,如果同步线程阻塞了当前线程,则它必须等待同步线程中的任务完成执行. 返回后,可以继续执行下一个任务;而异步线程不必等待.

ccriticalsection 多线程 死锁_死锁举例_死锁

仅凭这几句话仍然很难理解,因此我准备了很多案例,可以在分析时理解.

GCD API有很多,这里只介绍本文中使用的那些.

系统标准提供的两个队列

 // 全局队列,也是一个并行队列
 dispatch_get_global_queue 
 // 主队列,在主线程中运行,因为主线程只有一个,所以这是一个串行队列
 dispatch_get_main_queue 

此外,您还可以生成自己的队列

 // 从DISPATCH_QUEUE_SERIAL看出,这是串行队列
 dispatch_queue_create("com.demo.serialQueue", DISPATCH_QUEUE_SERIAL) 
 // 同理,这是一个并行队列
 dispatch_queue_create("com.demo.concurrentQueue", DISPATCH_QUEUE_CONCURRENT) 

接下来是创建同步线程和异步线程:

dispatch_sync(..., ^(block)) // 同步线程
dispatch_async(..., ^(block)) // 异步线程

假设您已基本了解上述知识,然后进入案例说明阶段.

NSLog(@"1"); // 任务1
dispatch_sync(dispatch_get_main_queue(), ^{
    NSLog(@"2"); // 任务2
});
NSLog(@"3"); // 任务3

结果,控制台输出:

1

死锁_ccriticalsection 多线程 死锁_死锁举例

分析:

dispatch_sync表示是一个同步线程;
dispatch_get_main_queue表示运行在主线程中的主队列;
任务2是同步线程的任务。

首先执行任务1,这绝对没有问题,但是接下来,程序遇到同步线程,然后它将进入等待状态,等待任务2完成,然后执行任务3. 但这是一个队列. 当然,当任务到达时,该任务将被添加到队列的末尾,然后按照FIFO原理执行该任务. 然后,现在将任务2添加到末尾,任务3排在任务2的前面,问题来了:

任务3要等任务2执行完才能执行,任务2由排在任务3后面,意味着任务2要在任务3执行完才能执行,所以他们进入了互相等待的局面。【既然这样,那干脆就卡在这里吧】这就是死锁。

技术分享

NSLog(@"1"); // 任务1
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    NSLog(@"2"); // 任务2
});
NSLog(@"3"); // 任务3

结果,控制台输出:

1
2
3

分析:

首先执行任务1,然后遇到同步线程,程序将进入等待状态. 等待任务2完成,然后再执行任务3. 从dispatch_get_global_queue可以看出,任务2已添加到全局并行队列中. 并行队列执行任务2后,它将返回主队列并继续执行任务3.

技术分享

dispatch_queue_t queue = dispatch_queue_create("com.demo.serialQueue", DISPATCH_QUEUE_SERIAL);
NSLog(@"1"); // 任务1
dispatch_async(queue, ^{
    NSLog(@"2"); // 任务2
    dispatch_sync(queue, ^{  
        NSLog(@"3"); // 任务3
    });
    NSLog(@"4"); // 任务4
});
NSLog(@"5"); // 任务5

ccriticalsection 多线程 死锁_死锁_死锁举例

结果,控制台输出:

1
5
2
// 5和2的顺序不一定

分析:

在这种情况下,未使用系统提供的串行或并行队列,而是由dispatch_queue_create函数创建了DISPATCH_QUEUE_SERIAL的串行队列.

执行任务1;
遇到异步线程,将【任务2、同步线程、任务4】加入串行队列中。因为是异步线程,所以在主线程中的任务5不必等待异步线程中的所有任务完成;
因为任务5不必等待,所以2和5的输出顺序不能确定;
任务2执行完以后,遇到同步线程,这时,将任务3加入串行队列;
又因为任务4比任务3早加入串行队列,所以,任务3要等待任务4完成以后,才能执行。但是任务3所在的同步线程会阻塞,所以任务4必须等任务3执行完以后再执行。这就又陷入了无限的等待中,造成死锁。

技术分享

NSLog(@"1"); // 任务1
dispatch_async(dispatch_get_global_queue(0, 0), ^{
    NSLog(@"2"); // 任务2
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"3"); // 任务3
    });
    NSLog(@"4"); // 任务4
});
NSLog(@"5"); // 任务5

结果,控制台输出:

1
2
5
3
4
// 5和2的顺序不一定

分析:

首先,将[任务1,异步线程,任务5]添加到主队列中. 异步线程中的任务是: [任务2,同步线程死锁举例,任务4].

因此,首先执行任务1,然后将异步线程中的任务添加到全局队列中. 由于存在异步线程,因此任务5不必等待,结果是2和5的输出顺序不一定.

死锁举例_ccriticalsection 多线程 死锁_死锁

然后查看异步线程中任务的执行顺序. 执行任务2后,它将遇到同步线程. 同步线程中的任务已添加到主队列中,此时添加的任务3位于任务5后面.

任务3执行完毕后,没有任何阻塞,程序继续执行任务4.

从上面的分析中,获得了几个结果: 1首先执行; 2首先执行. 2和5的顺序不是必需的; 4必须落后于3.

技术分享

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    NSLog(@"1"); // 任务1
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"2"); // 任务2
    });
    NSLog(@"3"); // 任务3
});
NSLog(@"4"); // 任务4
while (1) {
}
NSLog(@"5"); // 任务5

结果,控制台输出:

1
4
// 1和4的顺序不一定

分析:

与上述情况的分析类似,让我们看一下将哪些任务添加到主队列中: [异步线程,任务4,无限循环,任务5].

添加到全局队列异步线程的任务是: [任务1,同步线程,任务3].

第一个是异步线程. 任务4不需要等待,因此任务1和任务4的顺序不一定是结果.

任务4完成后,程序进入无限循环并进入主队列块. 但是,添加到全局队列的异步线程不会受到影响,并继续执行任务1后面的同步线程.

在同步线程中,任务2被添加到主线程中,并且直到任务2完成才可以执行任务3. 这时,主线程已被无限循环阻塞. 因此,无法执行任务2,当然也不能执行任务3,并且不会执行无限循环之后的任务5.

最后,您只能得到乱序的结果.

技术分享


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-228133-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      热点图片
      拼命载入中...