所以,我正在阅读这篇文章并且一些答案表明NSMutableArray
不是thread-safe
,但我找不到正确的答案来解决我遇到的问题。
将这个精简代码作为一个例子:
__block NSDictionary *remoteMediaFilesKeyedByRemotePath = [NSDictionary dictionaryWithObjects:remoteFiles forKeys:[remoteFiles valueForKey:@"remotePath"]];
__block NSMutableArray *changes = [NSMutableArray array];
[localFiles enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(ABSMediaFile *localFile, NSUInteger idx, BOOL *stop) {
ABSMediaFile *existingRemoteFile = remoteMediaFilesKeyedByRemotePath[localFile.remotePath];
if (existingRemoteFile != nil) {
[changes addObject:existingRemoteFile];
}
}];
当我尝试运行它时,应用程序在线程中执行一些操作,然后在addObject
行上轰炸:
malloc: *** error for object 0x102177438: incorrect checksum for freed object - object was probably modified after being freed.
任何人都可以澄清我是否最好单独使用快速枚举(单线程)或者是否有办法修复上述代码?
我想在循环中放置一个互斥量有点在第一时间失去并发枚举的目的。
OSX 10.9,Xcode 5。
答案 0 :(得分:2)
文档确实为NSEnumerationConcurrent
说明:
...阻止并发调用的代码必须是安全的。
您的块依赖于共享资源(仅限于此),因此我认为不值得尝试将此并发。正如您所提到的,NSMutableArray
本质上是线程不安全的,并且在块中添加互斥锁会使并发操作变得毫无价值。
因此,我建议使用快速枚举,因为:
__block NSDictionary *remoteMediaFilesKeyedByRemotePath = [NSDictionary dictionaryWithObjects:remoteFiles forKeys:[remoteFiles valueForKey:@"remotePath"]];
__block NSMutableArray *changes = [NSMutableArray array];
for (ABSMediaFile* localFile in localFiles) {
ABSMediaFile *existingRemoteFile = remoteMediaFilesKeyedByRemotePath[localFile.remotePath];
if (existingRemoteFile) {
[changes addObject:existingRemoteFile];
}
}];
答案 1 :(得分:1)
NSArray *enumeratedArray = @[@(1), @(2), @(3), @(4), @(5)];
NSMutableArray *array = [NSMutableArray new];
dispatch_semaphore_t addSemaphore = dispatch_semaphore_create(1);
[enumeratedArray enumerateObjectsWithOptions:NSEnumerationConcurrent
usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
// my concurrent operation
if ( 0 == ([obj integerValue] % 2) )
{
// mutable containers is NOT thread safe, need synchronize add or remove operation
dispatch_semaphore_wait(addSemaphore, DISPATCH_TIME_FOREVER);
[array addObject:obj];
dispatch_semaphore_signal(addSemaphore);
}
}];
// not need for ARC
//dispatch_release(addSemaphore);