多线程进阶

1.线程死锁问题

1)

dispatch_sync(dispatch_get_main_queue(), ^{

        NSLog(@"1111");

    });

结果:会死锁,崩溃

原因:sync同步队列会阻塞当前线程(主线程),直到block里的任务完成。而执行任务的主线程已经被阻塞,不能在执行任务,所以就会死锁。

2)

  dispatch_queue_t queue =  dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);

    dispatch_sync(queue, ^{

        dispatch_sync(dispatch_get_main_queue(), ^{

        NSLog(@"1111");

        });

        NSLog(@"之后 - %@",[NSThread currentThread]);

        NSLog(@"222");

    });

结果:会阻塞当前线程,但是不会死锁崩溃;

原因:阻塞的是异步线程,执行任务的是主线程

3)

  dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);

    dispatch_async(queue, ^{

        NSLog(@"2-----%@",[NSThread currentThread]);

        dispatch_sync(queue, ^{

          NSLog(@"3-----%@",[NSThreadcurrentThread]);

        });

    });

结果:会造成死锁崩溃。

原因:sync会阻塞当前的线程,即

4)????????

 dispatch_queue_tqueue =  dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);

    dispatch_async(queue, ^{

        NSLog(@"11---%@",[NSThread currentThread]);

        dispatch_queue_tqueue1 =  dispatch_queue_create("test",DISPATCH_QUEUE_SERIAL);


        dispatch_sync(queue1, ^{

        NSLog(@"22---%@",[NSThread currentThread]);

        });

        dispatch_sync(queue1, ^{

          NSLog(@"33---%@",[NSThread currentThread]);

        });


    });

2.线程锁及其性能

来源:iOS中保证线程安全的几种方式与性能对比 -

iOS的线程安全与锁 - CocoaChina_让移动开发更简单

不再安全的 OSSpinLock | Garan no dou

深入理解 iOS 开发中的锁

@synchronized、NSLock、dispatch_semaphore、NSCondition、pthread_mutex、OSSpinLock

性能对比:

OSSpinLock: 46.15 ms

dispatch_semaphore:          56.50 ms

pthread_mutex:                    178.28 ms

NSCondition:                          193.38 ms

NSLock:                                  175.02 ms

pthread_mutex(recursive):  172.56 ms

NSRecursiveLock:                  157.44 ms

NSConditionLock:                  490.04 ms

@synchronized:                      371.17 ms

1)OSSpinLock

自旋锁的实现原理比较简单,就是死循环。当a线程获得锁以后,b线程想要获取锁就需要等待a线程释放锁。在没有获得锁的期间,b线程会一直处于忙等的状态。如果a线程在临界区的执行时间过长,则b线程会消耗大量的cpu时间,不太划算。所以,自旋锁用在临界区执行时间比较短的环境性能会很高。

主要原因发生在低优先级线程拿到锁时,高优先级线程进入忙等(busy-wait)状态,消耗大量 CPU 时间,从而导致低优先级线程拿不到 CPU 时间,也就无法完成任务并释放锁。这种问题被称为优先级反转。

2)dispatch_semaphore

dispatch_semaphore实现的原理和自旋锁有点不一样。首先会先将信号量减一,并判断是否大于等于0,如果是,则返回0,并继续执行后续代码,否则,使线程进入睡眠状态,让出cpu时间。直到信号量大于0或者超时,则线程会被重新唤醒执行后续操作。

dispatch_semaphore_t lock = dispatch_semaphore_create(1);    //创建信号量

 dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);  //降低信号量  等于0时需要等待

//需要执行的代码

dispatch_semaphore_signal(lock);    //提升信号量


3)pthread_mutex

互斥锁的实现原理与信号量非常相似,不是使用忙等,而是阻塞线程并睡眠,需要进行上下文切换。

4)NSLock

NSLock 只是在内部封装了一个 pthread_mutex,属性为 PTHREAD_MUTEX_ERRORCHECK,它会损失一定性能换来错误提示。

5)@synchronized

这其实是一个 OC 层面的锁, 主要是通过牺牲性能换来语法上的简洁与可读。

我们知道 @synchronized 后面需要紧跟一个 OC 对象,它实际上是把这个对象当做锁来使用。这是通过一个哈希表来实现的,OC 在底层使用了一个互斥锁的数组(你可以理解为锁池),通过对对象去哈希值来得到对应的互斥锁。

你可能感兴趣的:(多线程进阶)