简体   繁体   中英

NSFileManager infinite cycling on iOS7

I'm very new to both iOS and Objective-C development, and I've been tasked with porting an application from iOS 6 to iOS 7. One of the immediately obvious issues is an apparent race condition that causes the app to lock up and eventually crash. The app starts successfully ~75% of the time, and hangs ~25% of the time on iOS7 devices; we have never encountered this behavior on iOS6 devices.

Using the debugger, I've narrowed it down to what appears to be an issue in 'ImageLoader'. I'm having trouble figuring out if this is part of an Apple API or an external library - I'm not able to find Apple documentation on it, but I also can't find it as a library anywhere, and use of the ImageLoader is a direct result of using the Apple API: [[NSFileManager defaultManager] createFileAtPath:_filePath contents:NULL attributes:NULL];

When the lock occurs, there are two threads accessing the ImageLoader. Both are a few steps down from ImageLoader::recursiveInitialization(). One is stuck in ImageLoader::recursiveSpinLock() (specifically 'dyld`OSAtomicCompareAndSwapLongBarrier'), while the other is stuck in 'libsystem_kernel.dylib`__psynch_mutexwait:'. What seems most likely to me is that this is an improperly implemented mutex, possibly at the kernel.

One of the threads is the main application thread, and I can walk through that code easily. The other thread is always the second thread created by the application, and contains no application code; I'm uncertain how to figure out where or how it is being created.

Relevant code:

[[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];

In short: this code removes the file at _filePath + ".tmp", moves the file at _filePath to _filePath + ".tmp", gets a read handle on _filePath + ".tmp", and finally creates a new file at _filePath. It locks at the last line in this code block and does not progress any further. It seems like fairly mundane code, so I'm wondering if there are some OS quirks that I'm missing due to inexperience.

I've done quite a bit of searching and haven't found anyone else with a similar issue. Does anyone have any ideas why this might be happening, or some steps I could take to further troubleshoot this?

Edit: I discovered that this code dispatches two threads that may use the ImageLoader at the same time. By modifying that code to operate on the same thread (ie synchronously), this error is avoided.~~

This still appears to me to be a bug within the ImageLoader code - the stack trace indicates a locking/mutex mechanism, but clearly it is not sufficiently thread-safe.

Edit 2: Never mind. I only managed to reduce the frequency - this is still happening, but 'only' around 10% of the time after removing the thread dispatch code.

I would try using different NSFileManager objects on the different threads. Instead of using [NSFileManager defaultManager], create separate instances with [[NSFileManager alloc] init]. See if that helps. The documentation says you should be able to use the same instance on different threads unless you are using delegates. But by trying to use different instances it should help verify if the error is happening in your code or not.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM