可能遇到的问题
- 数据不一致:在多线程环境下,当一个线程正在使用迭代器遍历数据时,另一个线程可能会对数据进行修改(如添加、删除元素),这会导致迭代器处于不一致的状态,例如跳过元素或者访问已删除的元素。
- 迭代器失效:同样因为其他线程对数据结构的修改,可能导致迭代器失效,使得后续操作引发未定义行为。
解决方法
- 加锁:使用互斥锁(如
NSLock
)来保护对数据结构的访问。在开始遍历和修改数据前获取锁,操作完成后释放锁。
- 使用线程安全的数据结构:例如
NSMutableArray
不是线程安全的,可考虑使用 NSConcurrentMutableArray
,它内部实现了线程安全机制,允许在多线程环境下安全地遍历和修改。
代码示例 - 使用锁
#import <Foundation/Foundation.h>
@interface ThreadSafeIterator : NSObject
@property (nonatomic, strong) NSMutableArray *dataArray;
@property (nonatomic, strong) NSLock *lock;
- (instancetype)initWithData:(NSMutableArray *)data;
- (void)traverseData;
@end
@implementation ThreadSafeIterator
- (instancetype)initWithData:(NSMutableArray *)data {
self = [super init];
if (self) {
_dataArray = data;
_lock = [[NSLock alloc] init];
}
return self;
}
- (void)traverseData {
[self.lock lock];
for (id obj in self.dataArray) {
NSLog(@"%@", obj);
}
[self.lock unlock];
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSMutableArray *array = [NSMutableArray arrayWithObjects:@"One", @"Two", @"Three", nil];
ThreadSafeIterator *iterator = [[ThreadSafeIterator alloc] initWithData:array];
dispatch_queue_t queue1 = dispatch_queue_create("com.example.queue1", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t queue2 = dispatch_queue_create("com.example.queue2", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue1, ^{
[iterator traverseData];
});
dispatch_async(queue2, ^{
[self.lock lock];
[array addObject:@"Four"];
[self.lock unlock];
});
}
return 0;
}
代码示例 - 使用线程安全的数据结构
#import <Foundation/Foundation.h>
@interface SafeTraversal : NSObject
@property (nonatomic, strong) NSConcurrentMutableArray *dataArray;
- (instancetype)initWithData:(NSArray *)data;
- (void)traverseData;
@end
@implementation SafeTraversal
- (instancetype)initWithData:(NSArray *)data {
self = [super init];
if (self) {
_dataArray = [NSConcurrentMutableArray arrayWithArray:data];
}
return self;
}
- (void)traverseData {
[self.dataArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(@"%@", obj);
}];
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSArray *array = @[@"One", @"Two", @"Three"];
SafeTraversal *traversal = [[SafeTraversal alloc] initWithData:array];
dispatch_queue_t queue1 = dispatch_queue_create("com.example.queue1", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t queue2 = dispatch_queue_create("com.example.queue2", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue1, ^{
[traversal traverseData];
});
dispatch_async(queue2, ^{
[traversal.dataArray addObject:@"Four"];
});
}
return 0;
}