死锁面试题(什么是死锁,产生死锁的原因及必要条件)

本文介绍了死锁相关知识。死锁指多个进程争夺资源造成的僵局,若无外力无法推进。产生死锁的原因包括竞争资源(不可剥夺资源和临时资源)和进程间推进顺序非法。死锁产生需满足互斥、请求和保持、不剥夺、环路等待4个必要条件。

什么是死锁?

  • 所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。

产生死锁的原因?

可归结为如下两点:

a. 竞争资源

  • 系统中的资源可以分为两类:
    1. 可剥夺资源,是指某进程在获得这类资源后,该资源可以再被其他进程或系统剥夺,CPU和主存均属于可剥夺性资源;
    2. 另一类资源是不可剥夺资源,当系统把这类资源分配给某进程后,再不能强行收回,只能在进程用完后自行释放,如磁带机、打印机等。

  • 产生死锁中的竞争资源之一指的是竞争不可剥夺资源(例如:系统中只有一台打印机,可供进程P1使用,假定P1已占用了打印机,若P2继续要求打印机打印将阻塞)

  • 产生死锁中的竞争资源另外一种资源指的是竞争临时资源(临时资源包括硬件中断、信号、消息、缓冲区内的消息等),通常消息通信顺序进行不当,则会产生死锁

b. 进程间推进顺序非法

  • 若P1保持了资源R1,P2保持了资源R2,系统处于不安全状态,因为这两个进程再向前推进,便可能发生死锁

  • 例如,当P1运行到P1:Request(R2)时,将因R2已被P2占用而阻塞;当P2运行到P2:Request(R1)时,也将因R1已被P1占用而阻塞,于是发生进程死锁

死锁产生的4个必要条件?

  • 产生死锁的必要条件:

    1. 互斥条件
    2. 请求和保持条件
    3. 不剥夺条件
    4. 环路等待条件。
在 iOS 开发中,死锁是一个常见但严重的并发问题,通常出现在多线程编程中,尤其是在使用 `GCD`(Grand Central Dispatch)或 `NSOperationQueue` 时。以下是与死锁相关的典型面试题及解答。 --- ### 什么是死锁死锁发生的四个必要条件是什么? 死锁是指两个或多个线程在执行过程中,因争夺资源而造成的一种相互等待的现象,导致它们都无法继续执行下去。在 iOS 开发中,死锁常出现在主线程中调用同步方法导致无法继续执行的情况。 死锁发生的四个必要条件是: 1. **互斥**:资源不能共享,一次只能被一个线程占用。 2. **持有并等待**:线程在等待其他资源时,不释放已持有的资源。 3. **不可抢占**:资源只能由持有它的线程主动释放,不能被强制剥夺。 4. **循环等待**:存在一个线程链,每个线程都在等待下一个线程所持有的资源。 --- ### 请举例说明在 iOS 中如何造成死锁? 一个常见的例子是使用 `dispatch_sync` 在主线程上同步执行任务: ```objective-c dispatch_queue_t mainQueue = dispatch_get_main_queue(); dispatch_sync(mainQueue, ^{ NSLog(@"This is a deadlock"); }); ``` 由于 `dispatch_sync` 会阻塞当前线程直到任务完成,而当前线程是主线程,任务又需要在主线程执行,因此主线程被阻塞,任务无法执行,造成死锁[^3]。 --- ### 如何避免死锁? 避免死锁的常见方法包括: - **避免嵌套锁**:尽量不要在一个锁的保护范围内再去申请另一个锁。 - **使用异步调用**:在多线程编程中,使用 `dispatch_async` 而非 `dispatch_sync` 可以有效避免死锁。 - **资源有序申请**:确保所有线程以相同的顺序申请资源,打破循环等待条件。 - **设置超时机制**:在申请资源时设置超时时间,防止无限期等待。 --- ### 在 GCD 中如何安全地进行线程通信? 推荐使用 `dispatch_async` 来进行线程通信,而不是 `dispatch_sync`。例如: ```objective-c dispatch_queue_t backgroundQueue = dispatch_queue_create("com.example.background", 0); dispatch_async(backgroundQueue, ^{ // 执行耗时任务 dispatch_async(dispatch_get_main_queue(), ^{ // 回到主线程更新 UI }); }); ``` 这样可以确保任务异步执行,不会阻塞当前线程,从而避免死锁的发生[^3]。 --- ### 使用 NSOperationQueue 时如何避免死锁? 在使用 `NSOperationQueue` 时,应避免在当前操作中等待另一个操作完成,尤其是当它们属于同一个队列时。可以通过设置依赖关系或使用异步方式处理。 例如,设置操作依赖: ```objective-c NSOperationQueue *queue = [[NSOperationQueue alloc] init]; NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"Operation 1"); }]; NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"Operation 2"); }]; [operation2 addDependency:operation1]; // operation2 依赖 operation1 [queue addOperation:operation1]; [queue addOperation:operation2]; ``` 通过这种方式,可以避免因手动等待而导致的死锁问题。 --- ### 在 iOS 开发中,主线程死锁的常见场景有哪些? 常见场景包括: - 在主线程中调用 `dispatch_sync` 到主线程队列。 - 使用 `NSURLConnection sendSynchronousRequest:returningResponse:error:` 同步请求阻塞主线程。 - 在 `NSOperation` 中使用 `waitUntilAllOperationsAreFinished:` 阻塞主线程。 --- ### 使用 semaphore 时如何避免死锁? 在使用 `dispatch_semaphore_t` 时,需确保每次调用 `dispatch_semaphore_wait` 都有对应的 `dispatch_semaphore_signal`,否则可能导致线程永久阻塞。例如: ```objective-c dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); dispatch_async(dispatch_get_global_queue(0, 0), ^{ // 模拟耗时任务 dispatch_semaphore_signal(semaphore); }); dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); ``` 确保信号量的 `wait` `signal` 成对出现,避免因未唤醒而导致死锁。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_长风_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值