简体   繁体   中英

Best way to do a “dirty read” of an object that may be locked by another thread in objective-c

I was wondering if the following is the best way to read and make a copy an object that may be locked by another thread?

-(NSObject*) getCopyOfActiveObjectsOfType:(Class) objectClass
{
    NSMutableArray* copy = [NSMutableArray arrayWithArray:[self.activeObjects objectForKey:objectClass]];

    return copy;
}

I have several methods like the following that lock the object in question to add or remove objects to the array.

-(void) addObject:(NSObject *)object toPoolOfObjects:(NSMutableDictionary*) objects
{
    Class objectClass = [object class];
    @synchronized (objects)
    {
        NSMutableArray* objectArray = [objects objectForKey:objectClass];

        if(objectArray == nil)
        {
            objectArray = [[[NSMutableArray alloc] init] autorelease];
            [objects setObject:objectArray forKey:objectClass];
        }
        [objectArray addObject:object];
    }

}

Using the @synchronize method or equivalent in alternate languages:

  • if your instance is accessed from multiple threads and it is not immutable , you will require synchronization blocks around all methods accessing state that can be be mutated
    • your object is immutable if none of the accessors / methods change the internal state of the object.

You are using standard NSMutableArray / NSMutableDictionary primitives for state, however these are not thread safe and therefore require locks when shared across threads. Without knowing the access vs update frequency for your API and it's consumers, it is difficult to recommend a specific solution.

If your API is mostly reads, you could get away with the following solution, which implements a copy on write. Though as always, you must profile to determine if the solution meets your performance requirements.

- (NSArray *)getActiveObjectsOfType:(Class)objectClass {
    @synchronize(self.activeObjects) {
        return [self.activeObjects objectForKey:objectClass];
    }
}

- (void)addObject:(NSObject *)object {
    Class objectClass = [object class];

    // synchronize access to activeObjects
    @synchronize(self.activeObjects) {
        NSArray *existingArray = [[[self.activeObjects objectForKey:objectClass] retain] autorelease];

        NSMutableArray *newArray;
        if (existingArray) {
            newArray = [NSMutableArray arrayWithArray:existingArray];
        } else {
            newArray = [NSMutableArray array];
        }

        [newArray addObject:object];

        [self.activeObjects setObject:newArray forKey:objectClass];
    }
}

What is important to note with this solution is the NSArray returned by getActiveObjectsOfType is immutable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM