我对iOS和Objective-C开发都很陌生,我的任务是将应用程序从iOS 6移植到iOS 7.一个明显的问题是明显的竞争条件导致应用程序锁定并最终崩溃。该应用程序成功启动~75%的时间,并且在iOS7设备上挂起约25%的时间;我们从未在iOS6设备上遇到过这种行为。
使用调试器,我已将其缩小到“ImageLoader”中的问题。我无法弄清楚这是Apple API还是外部库的一部分 - 我无法在其上找到Apple文档,但我也无法在任何地方找到它,并使用ImageLoader是使用Apple API的直接结果:[[NSFileManager defaultManager] createFileAtPath:_filePath contents:NULL attributes:NULL];
发生锁定时,有两个线程访问ImageLoader。两者距离ImageLoader :: recursiveInitialization()只有几步之遥。一个是卡在ImageLoader :: recursiveSpinLock()(特别是'dyld`OSAtomicCompareAndSwapLongBarrier'),而另一个卡在'libsystem_kernel.dylib`__psynch_mutexwait:'中。对我来说最可能的是,这是一个不正确实现的互斥锁,可能在内核中。
其中一个主题是主应用程序线程,我可以轻松地完成该代码。另一个线程始终是应用程序创建的第二个线程,不包含应用程序代码;我不确定如何弄清楚它的创建地点和方式。
相关代码:
[[NSFileManager defaultManager] removeItemAtPath:[_filePath stringByAppendingString:tmp] error:nil];
if (![[NSFileManager defaultManager] moveItemAtPath:_filePath toPath:[_filePath stringByAppendingString:tmp] error:nil]) {
return;
}
NSFileHandle *read = [NSFileHandle fileHandleForReadingAtPath:[_filePath stringByAppendingString:tmp]];
[[NSFileManager defaultManager] createFileAtPath:_filePath contents:NULL attributes:NULL];
简而言之:此代码删除_filePath +“。tmp”处的文件,将_filePath处的文件移动到_filePath +“。tmp”,获取_filePath +“.tmp”的读取句柄,最后创建一个新文件在_filePath。它锁定在此代码块的最后一行,并且不再继续进行。它似乎是相当普通的代码,所以我想知道是否有一些操作系统怪癖因缺乏经验而缺少。
我已经做了很多搜索,并没有找到其他人有类似的问题。有没有人知道为什么会发生这种情况,或者我可以采取哪些步骤来进一步解决这个问题?
编辑:我发现此代码会调度两个可能同时使用ImageLoader的线程。通过修改该代码以在同一线程上运行(即同步),可以避免这种错误.~~
这在我看来仍然是ImageLoader代码中的一个错误 - 堆栈跟踪指示锁定/互斥锁机制,但显然它没有足够的线程安全。
编辑2:没关系。我只是设法降低频率 - 这仍然在发生,但在删除线程调度代码后,“仅”大约10%的时间。
答案 0 :(得分:1)
我会尝试在不同的线程上使用不同的NSFileManager对象。不使用[NSFileManager defaultManager],而是使用[[NSFileManager alloc] init]创建单独的实例。看看是否有帮助。文档说你应该能够在不同的线程上使用相同的实例,除非你使用委托。但是,通过尝试使用不同的实例,它应该有助于验证代码中是否发生了错误。