线程死锁浅析

情形1:

dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"不会执行");
    });

如果在主线程添加这段代码,即同步执行添加到主队列的block。这个函数会等block执行完毕返回主线程,再继续执行下面的代码,而block要等主线程返回才会执行,所以循环等待造成死锁。

如果改成异步就可以了,因为当前主线程的一次runloop会马上返回,下一次runloop则会执行主队列里的block。

dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"会执行");
    });

还有一个用于在主线程更新ui的方法,如果在主线程执行它,即使是同步的,也并不会造成死锁。

[self performSelectorOnMainThread:@selector(logTest) withObject:nil waitUntilDone:YES];

情形2:

关于operationqueue的。

NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"111");
    }];
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"222");
    }];
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"333");
    }];
    NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"444");
    }];
    NSArray *arr = [NSArray arrayWithObjects:
                    op1,
                    op2,
                    op3,
                    op4,
                    nil];
    [[NSOperationQueue mainQueue]addOperations:arr waitUntilFinished:NO];
    NSLog(@"2");

也是在主线程当中异步执行,所以以上代码会正常运行,并且运行按照顺序,因为主队列是串行队列。

结果:

2015-07-01 14:07:34.064 TestProject[1388:318202] 1
2015-07-01 14:07:34.065 TestProject[1388:318202] 2
2015-07-01 14:07:34.070 TestProject[1388:318202] 111
2015-07-01 14:07:34.071 TestProject[1388:318202] 222
2015-07-01 14:07:34.073 TestProject[1388:318202] 333
2015-07-01 14:07:34.073 TestProject[1388:318202] 444

如果改为同步执行,则会造成死锁:

NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"111");
    }];
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"222");
    }];
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"333");
    }];
    NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"444");
    }];
    NSArray *arr = [NSArray arrayWithObjects:
                    op1,
                    op2,
                    op3,
                    op4,
                    nil];
    [[NSOperationQueue mainQueue]addOperations:arr waitUntilFinished:YES];
    NSLog(@"2");

结果:

2015-07-01 14:10:48.577 TestProject[1423:335286] 1

主队列等待当前的运行循环结束,然后运行队列中的block,而当前运行循环在等待

addOperations 的返回,所以当前运行循环永远不会结束,所以主队列中的block永远不会执行到,程序就这样卡住了。

如果另外创建一个队列(不会是主队列),用同步执行的话:
<pre name="code" class="objc">NSLog(@"1");
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"111");
    }];
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"222");
    }];
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"333");
    }];
    NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"444");
    }];
    NSArray *arr = [NSArray arrayWithObjects:
                    op1,
                    op2,
                    op3,
                    op4,
                    nil];
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];//并发,顺序不定
    [queue addOperations:arr waitUntilFinished:YES];
    NSLog(@"2");

运行结果如下:


<pre name="code" class="objc">2015-07-01 14:14:44.417 TestProject[1480:353564] 1
2015-07-01 14:14:44.418 TestProject[1480:353689] 111
2015-07-01 14:14:44.418 TestProject[1480:353705] 444
2015-07-01 14:14:44.418 TestProject[1480:353690] 333
2015-07-01 14:14:44.419 TestProject[1480:353685] 222
2015-07-01 14:14:44.419 TestProject[1480:353564] 2

结果正常。因为新创建的队列是可以并发的,所以1,2,3,4的执行顺序不一定。


如果改为异步执行,同样正常执行,1,2,3,4block执行顺序不定,但函数会立即返回。
<pre name="code" class="objc">NSLog(@"1");
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"111");
    }];
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"222");
    }];
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"333");
    }];
    NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"444");
    }];
    NSArray *arr = [NSArray arrayWithObjects:
                    op1,
                    op2,
                    op3,
                    op4,
                    nil];
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];//并发,顺序不定
    [queue addOperations:arr waitUntilFinished:NO];
    NSLog(@"2");

运行结果:


<pre name="code" class="objc">2015-07-01 14:17:53.111 TestProject[1513:365712] 1
2015-07-01 14:17:53.112 TestProject[1513:365712] 2
2015-07-01 14:17:53.112 TestProject[1513:365832] 333
2015-07-01 14:17:53.112 TestProject[1513:365831] 111
2015-07-01 14:17:53.112 TestProject[1513:365837] 444
2015-07-01 14:17:53.113 TestProject[1513:365830] 222

即使主线程阻塞了,1,2,3,4也会正常执行。



情形3:
<pre name="code" class="objc">NSLog(@"1");
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"=================1");
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"=================2");
        });
        NSLog(@"=================3");
    });
    NSLog(@"2");
    while (1) {

    }

同步执行主队列的block不会执行,因为当前运行循环不会结束。由于是同步的,所以下面的====3也不会执行到。


运行结果:
<pre name="code" class="objc">2015-07-01 14:21:25.499 TestProject[1651:389143] 1
2015-07-01 14:21:25.499 TestProject[1651:389143] 2
2015-07-01 14:21:25.499 TestProject[1651:389172] =================1

如果改为异步在主线程执行,则====3会执行。


<pre name="code" class="objc">NSLog(@"1");
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"=================1");
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"=================2");
        });
        NSLog(@"=================3");
    });
    NSLog(@"2");
    while (1) {

    }

结果:


<pre name="code" class="objc">2015-07-01 14:24:54.855 TestProject[1687:402116] 1
2015-07-01 14:24:54.855 TestProject[1687:402116] 2
2015-07-01 14:24:54.855 TestProject[1687:402152] =================1
2015-07-01 14:24:54.855 TestProject[1687:402152] =================3

总结:


在主线程中不要同步执行在主队列中的block。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-11 06:25:32

线程死锁浅析的相关文章

线程系列08,实现线程锁的各种方式,使用lock,Montor,Mutex,Semaphore以及线程死锁

当涉及到多线程共享数据,需要数据同步的时候,就可以考虑使用线程锁了.本篇体验线程锁的各种用法以及线程死锁.主要包括: ※ 使用lock处理数据同步※ 使用Monitor.Enter和Monitor.Exit处理数据同步※ 使用Mutex处理进程间数据同步※ 使用Semaphore处理数据同步※ 线程死锁 □ 使用lock处理数据同步 假设有一个类,主要用来计算该类2个字段的商,在计算商的方法之内让被除数自减,即被除数有可能为零.使用lock语句块保证每次只有一个线程进入该方法. class Th

线程死锁

所谓的线程死锁,是指在多线程运行的过程中,线程1拥有锁a,而需要锁b来继续执行, 而此时,线程2拥有锁b而需要锁a来继续执行,那么此时会形成死锁,两个线程会同时等待. 在编程的过程中应尽量的避免线程死锁. 有时在面试中会要求写出一个死锁的程序演示,如下: 1 //写一个死锁程序 2 public class DeadLock { 3 //主程序执行 4 public static void main(String[] args) { 5 Thread thread1 = new Thread(n

在Linux下线程死锁的四个条件

一.死锁的原因和必要条件 1.死锁的概念 一般情况下,如果同一个线程先后两次调用lock,在第一次调用时,由于锁已经被占,该线程会挂起等待别的线程释放锁,然而锁正是被自己占着的,该线程又被挂起,没有机会释放锁,因此,就永远处于挂起等待状态了,这叫做死锁(Deadlock).另种典型的死锁情形是这样:线程A获 得了锁1,线程B获得了锁2,这时线程A调用lock试图获得锁2,结果是需要挂起等待线程B释放锁2,而这时线程B也调用lock试图获得锁1,结果是需要挂起等待线程A释放锁1,于是线程A和B都永

Java笔记六.线程同步、线程死锁

线程同步.线程死锁 在上一篇文章中,有一个模拟售卖火车票系统,在卖车票的程序代码中,极有可能碰到一种意外,就是同一张票号被打印两次多次,也可能出现打印出0甚至负数的票号.具体表现为:假设tickets的值为1的时候,线程1刚执行完if(tickets>0)这行代码,正准备执行下面的代码,就在这时,操作系统将CPU切换到了线程2上执行,此时tickets的值仍为1,线程2执行完上面两行代码,tickets的值变为0后,CPU又切回到了线程1上执行,线程1不会再执行if(tickets>0)这行代

JAVA笔记14__多线程共享数据(同步)/ 线程死锁 /

/** * 多线程共享数据 * 线程同步:多个线程在同一个时间段只能有一个线程执行其指定代码,其他线程要等待此线程完成之后才可以继续执行. * 多线程共享数据的安全问题,使用同步解决. * 线程同步两种方法: * 1.同步代码块 * synchronized(要同步的对象){ 要同步的操作 } * 2.同步方法 * public synchronized void method(){ 要同步的操作 } */ public class Main { public static void main(

atitit.线程死锁&#160;卡住无反应&#160;的原因in&#160;cmd调用的解决方案&#160;&#160;v3&#160;q39

atitit.线程死锁 卡住无反应 的原因in cmd调用的解决方案  v3 q39 1. 问题::线程死锁  卡住无反应1 1.1. 分类:: cmd调用,  net io  , file  io 调用, multi thread调用same var的时候儿..1 1.2. 原因readLine()是阻塞方法1 1.3. 调用same var1 2. 解决之道::2 2.1. 使用了cmd /k走死锁兰...改成个/c佐ok兰..2 2.2. Watchdog2 3. Ref3 1. 问题::

进程/线程死锁产生的原因以及如何避免死锁

线程死锁产生的必要条件: (1)互斥条件:一个资源每次只能被一个进程使用. (2)请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放. (3)不可剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺. (4)循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系. 如何避免死锁,这点我觉得Erlang模型值得参考.在编程过程中,有一些避免死锁的经验: (1) 等待某个资源时,使用超时机制(例如Erlang中的receive可以加一个超时): (2) 采用消息通信的通信机

GCD中的线程死锁问题

GCD 确实好用 ,很强大,相比NSOpretion 无法提供 取消任务的功能. 如此强大的工具用不好可能会出现线程死锁. 如下代码: - (void)viewDidLoad { [super viewDidLoad]; NSLog(@"=================4"); dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@"=================5"); }); NSLog(@"===

Atitit.线程 死锁 跑飞 的检测与自动解除 与手动解除死锁 java c# .net php javascript.

Atitit.线程 死锁 跑飞 的检测与自动解除 与手动解除死锁 java c# .net php javascript. 1. 现象::主程序卡住无反应,多行任务不往下执行 1 2. 原因::使用jv jprofile查看线程,原来俩个线程死锁了.. 1 3. Java的缺点,默认不能自动解除死锁 1 4. 自动检测与解除死锁::使用看门狗watchdog 2 4.1. 死锁检测算法(太麻烦,不推荐) 2 4.2. 硬件看门狗 2 4.3. 软件看门狗的实现--TIMER 2 4.4. LIN