MST

星途 面试题库

面试题:Objective-C中迭代器模式与多线程

在Objective-C的多线程环境下,使用迭代器模式遍历数据可能会遇到哪些问题?如何解决这些问题以确保线程安全?请结合代码示例说明。
50.0万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

可能遇到的问题

  1. 数据不一致:在多线程环境下,当一个线程正在使用迭代器遍历数据时,另一个线程可能会对数据进行修改(如添加、删除元素),这会导致迭代器处于不一致的状态,例如跳过元素或者访问已删除的元素。
  2. 迭代器失效:同样因为其他线程对数据结构的修改,可能导致迭代器失效,使得后续操作引发未定义行为。

解决方法

  1. 加锁:使用互斥锁(如 NSLock)来保护对数据结构的访问。在开始遍历和修改数据前获取锁,操作完成后释放锁。
  2. 使用线程安全的数据结构:例如 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;
}