问题描述
我目前正在通过调用
dispatch_async(my_queue,^{
[self writeToRoot:filename data:data];
};
- (BOOL)writeToRoot:(NSString *)path data:(NSData *)content
{
NSString *fullPath = [[self rootPath] stringByAppendingPathComponent:path];
NSString *pathWithoutFile = [fullPath stringByDeletingLastPathComponent];
BOOL directoryExists = [[NSFileManager defaultManager] fileExistsAtPath:pathWithoutFile];
if (!directoryExists) {
NSError *error = nil;
[[NSFileManager defaultManager] createDirectoryAtPath:pathWithoutFile
withIntermediateDirectories:YES
attributes:nil error:&error];
NSParameterAssert(error == nil);
}
return [content writeToFile:fullPath atomically:NO];
}
我这样做是因为它不会阻塞主线程.我的问题是如何确保线程安全.在执行此后台操作时,当我尝试通过调用以下命令从磁盘读取文件时会发生什么情况:
I am doing this so as it would not block the main thread. My question is how to ensure thread safety. while this background operation is being carried out, what happens when I try to read from disk the file by calling:
[NSData dataWithContentsOfFile:fullPath];
内容会被破坏吗?还是写操作会锁定文件,而读操作将等到写操作完成?
Will be content be corrupted?OR will the write operation lock the file and the read operation will wait until the writing is completed?
推荐答案
我倾向于对my_queue
进行dispatch_sync
的读取操作,以确保线程安全(假设它是串行队列).您还可以使用各种(例如锁或@synchronized
指令),但是考虑到您已经为文件交互设置了队列,使用该串行队列可能最简单.
I'd be inclined to dispatch_sync
your read operation to the my_queue
to ensure thread safety (assuming that it's a serial queue). You could also use any of the various synchronization tools (such as locks or @synchronized
directive), but given that you already have your queue set up for file interaction, using that serial queue is probably easiest.
部分.
顺便说一句,如果要保存在后台队列中(这意味着保存操作可能足够慢,不足以证明在后台进行保存是合理的),因此请确保您请求一点时间来完成操作在保存操作正在进行时,以防应用本身中断(即用户点击物理主页按钮,打进电话等)的操作.为此,您可以在分派保存操作之前调用beginBackgroundTaskWithExpirationHandler
,并在完成后调用endBackgroundTask
:
By the way, if you're saving in a background queue (which means that the save operation is presumably slow enough to justify doing it in the background) it might be prudent to make sure that you request a little time to complete the operation in case the app, itself, is interrupted (i.e. the user taps the physical home button, a call comes in, etc) while the save operation is in progress. You do this by calling beginBackgroundTaskWithExpirationHandler
before you dispatch the save operation, and call endBackgroundTask
when it's done:
UIApplication *application = [UIApplication sharedApplication];
// get background task identifier before you dispatch the save operation to the background
UIBackgroundTaskIdentifier __block task = [application beginBackgroundTaskWithExpirationHandler:^{
if (task != UIBackgroundTaskInvalid) {
[application endBackgroundTask:task];
task = UIBackgroundTaskInvalid;
}
}];
// now dispatch the save operation
dispatch_async(my_queue, ^{
// do the save operation here
// now tell the OS that you're done
if (task != UIBackgroundTaskInvalid) {
[application endBackgroundTask:task];
task = UIBackgroundTaskInvalid;
}
});
这将确保您的保存操作有很大的机会成功完成,即使该应用程序被中断了.
This will ensure that your save operation has a fighting chance to successfully complete, even if the app is interrupted.
而且,正如Jsdodgers指出的那样,您可能也想执行原子写入.
And, as Jsdodgers points out, you probably want to perform an atomic write, too.
这篇关于ios在后台线程上写入磁盘的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!