NSMutableArray + NSEnumerationConcurrent内存错误

时间:2014-02-01 15:22:45

标签: objective-c multithreading cocoa objective-c-blocks

所以,我正在阅读这篇文章并且一些答案表明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。

2 个答案:

答案 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);