Objective-c: problems with blocks and NSEnumerationConcurrent

I have a dictionary containing a second dictionary with 1000 entries. Entries are all NSStrings of a key of type = key XXX, and value = element XXX, where XXXis a number between 0 - the number of elements is 1. (A few days ago I asked about Objective-C dictionaries containing a dictionary to refer to this question if you want the code, which creates the dictionary.)

The total length of all lines in the additional dictionary is 28,670 characters. i.e:

strlen("key 0")+strlen("element 0")+
//and so on up through 
strlen("key 999")+strlen("element 999") == 28670. 

Consider this very simple hash value as an indicator if the method listed each key pair + value once and only once.

I have one subroutine that works fine (using blocks) to access a separate dictionary key and values:

NSUInteger KVC_access3(NSMutableDictionary *dict){
    __block NSUInteger ll=0;
    NSMutableDictionary *subDict=[dict objectForKey:@"dict_key"];

    [subDict 
        enumerateKeysAndObjectsUsingBlock:
            ^(id key, id object, BOOL *stop) {
                ll+=[object length];
                ll+=[key length];
    }];
    return ll;
}
// will correctly return the expected length...

( ), , , 28670:

NSUInteger KVC_access4(NSMutableDictionary *dict){
    __block NSUInteger ll=0;
    NSMutableDictionary *subDict=[dict objectForKey:@"dict_key"];

    [subDict 
        enumerateKeysAndObjectsWithOptions:
            NSEnumerationConcurrent
        usingBlock:
            ^(id key, id object, BOOL *stop) {
                ll+=[object length];
                ll+=[key length]; 
    }];
    return ll;
}
// will return correct value sometimes; a shortfall value most of the time...

Apple NSEnumerationConcurrent state:

 "the code of the Block must be safe against concurrent invocation."

, , , , KVC_access4, ?

BJ Homer , NSEnumerationConcurrent. . , KVC_access3, . . , mongo ( /), :

[subDict 
    enumerateKeysAndObjectsWithOptions:
        NSEnumerationConcurrent
    usingBlock:
        ^(id key, id object, BOOL *stop) {
        NSUInteger workingLength = [object length];
        workingLength += [key length];

        OSAtomicAdd64Barrier(workingLength, &ll); 
 }];

4 . 1 100 000 . , , - .

+5
1

. , ll. , .

, += . , ll += x - , ll = ll + x. ll, x , ll. , ll Thread X, , , , , Thread X .

, . :

__block NSUInteger ll=0;
NSMutableDictionary *subDict=[dict objectForKey:@"dict_key"];

[subDict 
    enumerateKeysAndObjectsWithOptions:NSEnumerationConcurrent
    usingBlock:
        ^(id key, id object, BOOL *stop) {
            @synchronized(subDict) { // <-- Only one thread can be in this block at a time.
                ll+=[object length];
                ll+=[key length];
            }
}];
return ll;

, , , -, .

concurrency , :

__block uint64 ll = 0; // Note the change in type here; it needs to be a 64-bit type.

^(id key, id object, BOOL *stop) {
    NSUInteger workingLength = [object length];
    workingLength += [key length];

    OSAtomicAdd64Barrier(workingLength, &ll); 
}

, OSAtomicAdd64Barrier, , . @synchronized , , , , , . , , .

+13

All Articles