面试题答案
一键面试可能出现的问题
- 数据竞争:多个线程同时读写文件,可能导致数据不一致。例如,一个线程正在写入文件,另一个线程同时读取,可能读取到不完整的数据。
- 文件损坏:如果多个线程同时写入文件,可能会导致文件内容混乱或损坏。
解决方案
- 使用锁机制:可以使用互斥锁(如
NSLock
、pthread_mutex
等)来保证同一时间只有一个线程可以访问文件。 - 队列操作:利用
NSOperationQueue
或DispatchQueue
,将文件操作任务添加到队列中,按顺序执行,避免并发操作。 - 使用文件专用线程:创建一个专门用于文件操作的线程,所有文件相关的操作都在这个线程中执行。
具体场景及代码示例
假设我们有一个应用程序,多个线程需要向同一个日志文件中写入日志。
使用NSLock示例
#import <Foundation/Foundation.h>
// 创建一个全局的NSLock对象
NSLock *fileLock = nil;
void writeLogToFile(NSString *logMessage) {
if (!fileLock) {
fileLock = [[NSLock alloc] init];
}
// 加锁
[fileLock lock];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *logFilePath = [documentsPath stringByAppendingPathComponent:@"log.txt"];
// 检查文件是否存在,不存在则创建
if (![fileManager fileExistsAtPath:logFilePath]) {
[fileManager createFileAtPath:logFilePath contents:nil attributes:nil];
}
// 写入日志
NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:logFilePath];
[fileHandle seekToEndOfFile];
[fileHandle writeData:[logMessage dataUsingEncoding:NSUTF8StringEncoding]];
[fileHandle writeData:[@"\n" dataUsingEncoding:NSUTF8StringEncoding]];
[fileHandle closeFile];
// 解锁
[fileLock unlock];
}
// 模拟多线程写入日志
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i = 0; i < 10; i++) {
dispatch_async(concurrentQueue, ^{
NSString *logMessage = [NSString stringWithFormat:@"Log message %d", i];
writeLogToFile(logMessage);
});
}
使用DispatchQueue示例
#import <Foundation/Foundation.h>
// 创建一个串行队列
dispatch_queue_t fileQueue = dispatch_queue_create("com.example.fileQueue", DISPATCH_QUEUE_SERIAL);
void writeLogToFile(NSString *logMessage) {
dispatch_sync(fileQueue, ^{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *logFilePath = [documentsPath stringByAppendingPathComponent:@"log.txt"];
if (![fileManager fileExistsAtPath:logFilePath]) {
[fileManager createFileAtPath:logFilePath contents:nil attributes:nil];
}
NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:logFilePath];
[fileHandle seekToEndOfFile];
[fileHandle writeData:[logMessage dataUsingEncoding:NSUTF8StringEncoding]];
[fileHandle writeData:[@"\n" dataUsingEncoding:NSUTF8StringEncoding]];
[fileHandle closeFile];
});
}
// 模拟多线程写入日志
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i = 0; i < 10; i++) {
dispatch_async(concurrentQueue, ^{
NSString *logMessage = [NSString stringWithFormat:@"Log message %d", i];
writeLogToFile(logMessage);
});
}
通过上述方法,可以有效避免多线程文件操作中的数据一致性问题,并在一定程度上提高性能。使用锁机制简单直接,但可能会影响性能;队列操作更适合复杂的任务调度和并发控制。