Lets say I want to make this code thread-safe:
- (void) addThing:(id)thing { // Can be called from different threads
[_myArray addObject:thing];
}
Ok, I done some more tests and here are results:
lock test: mean:2.48661, stdDev:0.50599
synchronized test: mean:2.51298, stdDev:0.49814
dispatch Test: mean:2.17046, stdDev:0.43199
So I was wrong, my bad :( If somebody is interested in test code it's avail here:
static NSInteger retCount = 0;
@interface testObj : NSObject
@end
@implementation testObj
-(id)retain{
retCount++;
return [super retain];
}
@end
@interface ViewController : UIViewController{
NSMutableArray* _a;
NSInteger _c;
NSLock* lock;
NSLock* thlock;
dispatch_queue_t _q;
}
- (IBAction)testBtn:(id)sender;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
-(NSTimeInterval)testCase:(SEL)aSel name:(NSString*)name{
_a = [[NSMutableArray alloc] init];
retCount = 0;
//Sync test
NSThread* th[10];
for(int t = 0; t < 10;t ++){
th[t] = [[NSThread alloc] initWithTarget:self selector:aSel object:nil];
}
NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate];
for(int t = 0; t < 10;t ++){
[th[t] start];
}
NSInteger thCount = 1;
while(thCount > 0){
thCount = 0;
for(int t = 0; t < 10;t ++){
thCount += [th[t] isFinished] ? 0 : 1;
}
}
NSTimeInterval end = [NSDate timeIntervalSinceReferenceDate];
NSLog(@"%@: %2.5f, retainCount:%d, _c:%d, objects:%d", name, end-start, retCount, _c, [_a count]);
[_a release];
for(int t = 0; t < 10;t ++){
[th[t] release];
}
return end-start;
}
-(void)syncTest{
for(int t = 0; t < 5000; t ++){
[self synchronizedAdd:[[[testObj alloc] init] autorelease] ];
}
}
-(void)dispTest{
for(int t = 0; t < 5000; t ++){
[self dispatchSyncAdd:[[[testObj alloc] init] autorelease] ];
}
}
-(void)lockTest{
for(int t = 0; t < 5000; t ++){
[self lockAdd:[[[testObj alloc] init] autorelease] ];
}
}
- (void) synchronizedAdd:(NSObject*)anObject
{
@synchronized(self) {
[_a addObject:anObject];
_c++;
}
}
- (void) dispatchSyncAdd:(NSObject*)anObject
{
dispatch_sync(_q, ^{
[_a addObject:anObject];
_c++;
});
}
- (void) lockAdd:(NSObject*)anObject
{
[lock lock];
[_a addObject:anObject];
_c++;
[lock unlock];
}
- (double)meanOf:(NSArray *)array
{
double runningTotal = 0.0;
for(NSNumber *number in array)
{
runningTotal += [number doubleValue];
}
return (runningTotal / [array count]);
}
- (double)standardDeviationOf:(NSArray *)array
{
if(![array count]) return 0;
double mean = [self meanOf:array];
double sumOfSquaredDifferences = 0.0;
for(NSNumber *number in array)
{
double valueOfNumber = [number doubleValue];
double difference = valueOfNumber - mean;
sumOfSquaredDifferences += difference * difference;
}
return sqrt(sumOfSquaredDifferences / [array count]);
}
-(void)stats:(NSArray*)data name:(NSString*)name{
NSLog(@"%@: mean:%2.5f, stdDev:%2.5f", name, [self meanOf:data], [self standardDeviationOf:data]);
}
- (IBAction)testBtn:(id)sender {
_q = dispatch_queue_create("array q", DISPATCH_QUEUE_SERIAL);
lock = [[NSLock alloc] init];
NSMutableArray* ltd = [NSMutableArray array];
NSMutableArray* std = [NSMutableArray array];
NSMutableArray* dtd = [NSMutableArray array];
for(int t = 0; t < 20; t++){
[ltd addObject: @( [self testCase:@selector(lockTest) name:@"lock Test"] )];
[std addObject: @( [self testCase:@selector(syncTest) name:@"synchronized Test"] )];
[dtd addObject: @( [self testCase:@selector(dispTest) name:@"dispatch Test"] )];
}
[self stats: ltd name:@"lock test"];
[self stats: std name:@"synchronized test"];
[self stats: dtd name:@"dispatch Test"];
}
@end