iOS多线程死锁错误的探究
多线程简介
iOS应用程序中的多线程可以使我们利用多个处理器同时运行任务,从而显著提高程序的性能。有一些场景太复杂或太耗时,必须使用多线程,否则会导致应用程序变得缓慢和不稳定。例如,当我们需要在后台更新UI元素时,使用多线程是非常必要的。 IOS提供了两个主要API以便我们创建多线程:dispatch queue 和Operation queue。前者使用 GCD(), 而后者使用 NSOperation 和 NSOperationQueue。这两个API下的多线程程序是很难避免死锁的。什么是死锁?
死锁指的是在两个或两个的并发进程中,他们因持有对方所需的、而该共享资源又只能被同一进程持有,从而造成的一种僵局;如果不采取其它措施,它们都将无法继续执行下去。 死锁背后的问题往往是取决于两个的进程试图获取共享资源而互相阻塞的情况。API 并发处理难免会遇到多个线程同时等待其他的线程情况,如果实现不当就会发生死锁现象。在 iOS 编程中,除了一些小巧的程序之外,基本上都会涉及线程锁的问题。下面让我们探究一些 iOS 多线程的死锁问题原因以及如何避免它们。避免多线程死锁的方法
1. 理解多线程的概念,及各种问题。 2. 确定线程执行的正确顺序。 3. 避免线程在主线程上执行长时间任务。 4. 在操作中使用锁。 5. 获取锁的顺序必须一致。 6. 注意锁的时机。 7. 避免递归锁。 8. 合理使用自旋锁。 更好地理解这些概括性容易理解但却没有参考详细实施方法的解决方法的建议,我们来看一下具体代码和场景,以便我们更好地理解如何实现它们以及如何避免死锁问题。示例分析
示例 1:多个线程请求同一资源 ```objective-c dispatch_queue_t queue1 = dispatch_queue_create(\"queue1\", DISPATCH_QUEUE_SERIAL); dispatch_queue_t queue2 = dispatch_queue_create(\"queue2\", DISPATCH_QUEUE_SERIAL); dispatch_async(queue1, ^{ NSLog(@\"dispatch_async: 1\"); dispatch_sync(queue2, ^{ NSLog(@\"dispatch_sync: 1.1\"); }); NSLog(@\"dispatch_async: 2\"); }); dispatch_async(queue2, ^{ NSLog(@\"dispatch_async: 2\"); dispatch_sync(queue1, ^{ NSLog(@\"dispatch_sync: 2.1\"); }); NSLog(@\"dispatch_async: 3\"); }); ``` 代码中,我们首先定义了两个串行队列,queue1 和 queue2。接着,我们在 queue1 的异步块中执行了一段代码。不过,在此代码块内,我们启动另一个同步块,该同步块需要在 queue2 上执行。相反,当 queue2 执行时,我们还要启动另一个同步块,该同步块需要在 queue1 上执行。这段代码的意思是:我们在两个队列之间创建了一种相互依赖的关系,而这种依赖关系有可能是相互阻塞的。当我们运行该程序时,将会出现死锁的情况。 代码中的死锁根本原因就是:每个线程都正在等待对方首先释放资源,才能继续执行进程。 示例 2:并发任务彼此等待 ```objective-c @implementation ViewController { dispatch_queue_t _dataProcessQueue; dispatch_queue_t _imageProcessQueue; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. _dataProcessQueue = dispatch_queue_create(\"com.xxxxxx.dataProcessQueue\", DISPATCH_QUEUE_SERIAL); _imageProcessQueue = dispatch_queue_create(\"com.xxxxxx.imageProcessQueue\", DISPATCH_QUEUE_SERIAL); // _imageProcessQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); UIImage *image = [UIImage imageNamed:@\"example\"]; NSData *data = UIImageJPEGRepresentation(image, 1.0f); __block UIImage *aImage = nil; dispatch_async(_dataProcessQueue, ^{ NSData *processData = [NSData dataWithData:data]; [NSThread sleepForTimeInterval:2.0f]; dispatch_async(_imageProcessQueue, ^{ if (nil != processData) { aImage = [UIImage imageWithData:processData]; [NSThread sleepForTimeInterval:2.0f]; } }); NSLog(@\"Async process in data...%@\",[NSThread currentThread]); }); dispatch_async(_imageProcessQueue, ^{ while (YES) { if (aImage!=nil) { NSLog(@\"Success...%@\",[NSThread currentThread]); break; } else { NSLog(@\"waiting...%@\",[NSThread currentThread]); [NSThread sleepForTimeInterval:1.0f]; } } }); } ``` 代码中的死锁是由于两个并发任务彼此等待而阻塞了进程。第一个任务将数据处理过程放置到一个队列中,当处理完成后,它启动了对图像数据的处理。在这里,第二个任务必须在 _dataProcessQueue 任务完成之后才能处理 _imageProcessQueue 任务。这就是所谓的“竞争资源”,亦即应用程序的多个任务都在等待同一个资源的归还。由于这是一个阻塞操作,所以它在一定的情况下会造成死锁。 先生们,当我们编写高效的 iOS 多线程程序时,死锁问题会很常见。避免死锁的关键是正确执行多线程的使用方法。在示例中,我们探究了两个导致多线程死锁问题的原因,以及如何根据 API 功能调整线程运行顺序、避免在主线程上长时间运行、在操作中使用锁等,以减少这些类型的问题。我们强烈建议,大家在使用多线程时,请务必特别谨慎。不要让这些简单的错误毁对您的应用造成灾难性的损失。版权声明:《iOS多线程死锁(iOS多线程死锁错误的探究)》文章主要来源于网络,不代表本网站立场,不承担相关法律责任,如涉及版权问题,请发送邮件至3237157959@qq.com举报,我们会在第一时间进行处理。本文文章链接:http://www.bxwic.com/shcss/14108.html