DevSupportiOS开发 技术集锦

线程安全的NSMutableDictionary

2017-06-09  本文已影响332人  iOS104

NSDictionary是线程安全的,NSMutableDictionary是线程不安全的。
利用锁来保证线程的安全。

代码地址,欢迎star

测试方式:

现在有几种方式可以保证线程安全

在子线程串行执行结果:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        double then, now;
        
        then = CFAbsoluteTimeGetCurrent();
        for (NSUInteger i = 0; i < _iterationsCount; i++)
        {
            [_syncDictionary setObject:@(i) forKey:@(i)];
            [_syncDictionary objectForKey:@(i)];
        }
        now = CFAbsoluteTimeGetCurrent();
        
        dispatch_async(dispatch_get_main_queue(), ^{
            self.synchronizedLabel.text = [NSString stringWithFormat:@"@synchronized: %f sec\n", now-then];
        });
        
        
        then = CFAbsoluteTimeGetCurrent();
        for (NSUInteger i = 0; i < _iterationsCount; i++)
        {
            [_nsLockDictionary setObject:@(i) forKey:@(i)];
            [_nsLockDictionary objectForKey:@(i)];
        }
        now = CFAbsoluteTimeGetCurrent();
        
        dispatch_async(dispatch_get_main_queue(), ^{
            self.nsLockLabel.text = [NSString stringWithFormat:@"NSLock: %f sec\n", now-then];
        });
        
        then = CFAbsoluteTimeGetCurrent();
        for (NSUInteger i = 0; i < _iterationsCount; i++)
        {
            [_spinLockDictionary setObject:@(i) forKey:@(i)];
            [_spinLockDictionary objectForKey:@(i)];
        }
        now = CFAbsoluteTimeGetCurrent();
        
        dispatch_async(dispatch_get_main_queue(), ^{
            self.osSpinLockLabel.text = [NSString stringWithFormat:@"OSSpinLock: %f sec\n", now-then];
        });
        
        then = CFAbsoluteTimeGetCurrent();
        for (NSUInteger i = 0; i < _iterationsCount; i++)
        {
            [_semaphoreDictionary setObject:@(i) forKey:@(i)];
            [_semaphoreDictionary objectForKey:@(i)];
        }
        now = CFAbsoluteTimeGetCurrent();
        
        dispatch_async(dispatch_get_main_queue(), ^{
            self.gcdSemaphoreLabel.text = [NSString stringWithFormat:@"GCD Semaphore: %f sec\n", now-then];
        });
        
        then = CFAbsoluteTimeGetCurrent();
        for (NSUInteger i = 0; i < _iterationsCount; i++)
        {
            [_queueDictionary setObject:@(i) forKey:@(i)];
            [_queueDictionary objectForKey:@(i)];
        }
        now = CFAbsoluteTimeGetCurrent();
        
        dispatch_async(dispatch_get_main_queue(), ^{
            self.gcdQueueLabel.text = [NSString stringWithFormat:@"GCD Queue: %f sec\n", now-then];
        });
        
        then = CFAbsoluteTimeGetCurrent();
        for (NSUInteger i = 0; i < _iterationsCount; i++)
        {
            [_ptMutexDictionary setObject:@(i) forKey:@(i)];
            [_ptMutexDictionary objectForKey:@(i)];
        }
        now = CFAbsoluteTimeGetCurrent();
        
        dispatch_async(dispatch_get_main_queue(), ^{
            self.pthreadMutexLabel.text = [NSString stringWithFormat:@"PThread mutex: %f sec\n", now-then];
            
            self.twoBlockTestButton.enabled = YES;
            self.lockUnlockTestButton.enabled = YES;
        });
        
    });
image.png

线程安全的NSMutableDictionary,在两个并发的block中执行100000次set,get

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
        double then, now;
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
        
        then = CFAbsoluteTimeGetCurrent();
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (NSUInteger i = 0; i < _iterationsCount; i++)
            {
                [_syncDictionary setObject:@(i) forKey:@(i)];
                [_syncDictionary objectForKey:@(i)];
            }
            
            dispatch_semaphore_signal(semaphore);
        });
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (NSUInteger i = 0; i < _iterationsCount; i++)
            {
                [_syncDictionary setObject:@(i) forKey:@(i)];
                [_syncDictionary objectForKey:@(i)];
            }
            
            dispatch_semaphore_signal(semaphore);
        });
        
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        now = CFAbsoluteTimeGetCurrent();
        
        dispatch_async(dispatch_get_main_queue(), ^{
            self.synchronizedLabel.text = [NSString stringWithFormat:@"@synchronized: %f sec\n", now-then];
        });
        
        
        then = CFAbsoluteTimeGetCurrent();
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (NSUInteger i = 0; i < _iterationsCount; i++)
            {
                [_nsLockDictionary setObject:@(i) forKey:@(i)];
                [_nsLockDictionary objectForKey:@(i)];
            }
            
            dispatch_semaphore_signal(semaphore);
        });
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (NSUInteger i = 0; i < _iterationsCount; i++)
            {
                [_nsLockDictionary setObject:@(i) forKey:@(i)];
                [_nsLockDictionary objectForKey:@(i)];
            }
            
            dispatch_semaphore_signal(semaphore);
        });
        
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        
        now = CFAbsoluteTimeGetCurrent();
        
        dispatch_async(dispatch_get_main_queue(), ^{
            self.nsLockLabel.text = [NSString stringWithFormat:@"NSLock: %f sec\n", now-then];
        });
        
        then = CFAbsoluteTimeGetCurrent();
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (NSUInteger i = 0; i < _iterationsCount; i++)
            {
                [_spinLockDictionary setObject:@(i) forKey:@(i)];
                [_spinLockDictionary objectForKey:@(i)];
            }
            
            dispatch_semaphore_signal(semaphore);
        });
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (NSUInteger i = 0; i < _iterationsCount; i++)
            {
                [_spinLockDictionary setObject:@(i) forKey:@(i)];
                [_spinLockDictionary objectForKey:@(i)];
            }
            
            dispatch_semaphore_signal(semaphore);
        });
        
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        now = CFAbsoluteTimeGetCurrent();
        
        dispatch_async(dispatch_get_main_queue(), ^{
            self.osSpinLockLabel.text = [NSString stringWithFormat:@"OSSpinLock: %f sec\n", now-then];
        });
        
        then = CFAbsoluteTimeGetCurrent();
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (NSUInteger i = 0; i < _iterationsCount; i++)
            {
                [_semaphoreDictionary setObject:@(i) forKey:@(i)];
                [_semaphoreDictionary objectForKey:@(i)];
            }
            
            dispatch_semaphore_signal(semaphore);
        });
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (NSUInteger i = 0; i < _iterationsCount; i++)
            {
                [_semaphoreDictionary setObject:@(i) forKey:@(i)];
                [_semaphoreDictionary objectForKey:@(i)];
            }
            
            dispatch_semaphore_signal(semaphore);
        });
        
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        now = CFAbsoluteTimeGetCurrent();
        
        dispatch_async(dispatch_get_main_queue(), ^{
            self.gcdSemaphoreLabel.text = [NSString stringWithFormat:@"GCD Semaphore: %f sec\n", now-then];
        });
        
        then = CFAbsoluteTimeGetCurrent();
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (NSUInteger i = 0; i < _iterationsCount; i++)
            {
                [_queueDictionary setObject:@(i) forKey:@(i)];
                [_queueDictionary objectForKey:@(i)];
            }
            
            dispatch_semaphore_signal(semaphore);
        });
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (NSUInteger i = 0; i < _iterationsCount; i++)
            {
                [_queueDictionary setObject:@(i) forKey:@(i)];
                [_queueDictionary objectForKey:@(i)];
            }
            
            dispatch_semaphore_signal(semaphore);
        });
        
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        now = CFAbsoluteTimeGetCurrent();
        
        dispatch_async(dispatch_get_main_queue(), ^{
            self.gcdQueueLabel.text = [NSString stringWithFormat:@"GCD Queue: %f sec\n", now-then];
        });
        
        then = CFAbsoluteTimeGetCurrent();
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (NSUInteger i = 0; i < _iterationsCount; i++)
            {
                [_ptMutexDictionary setObject:@(i) forKey:@(i)];
                [_ptMutexDictionary objectForKey:@(i)];
            }
            
            dispatch_semaphore_signal(semaphore);
        });
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (NSUInteger i = 0; i < _iterationsCount; i++)
            {
                [_ptMutexDictionary setObject:@(i) forKey:@(i)];
                [_ptMutexDictionary objectForKey:@(i)];
            }
            
            dispatch_semaphore_signal(semaphore);
        });
        
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        now = CFAbsoluteTimeGetCurrent();
        
        dispatch_async(dispatch_get_main_queue(), ^{
            self.pthreadMutexLabel.text = [NSString stringWithFormat:@"PThread mutex: %f sec\n", now-then];
            
            self.twoBlockTestButton.enabled = YES;
            self.lockUnlockTestButton.enabled = YES;
        });
    });
image.png

在并发的线程安全的NSMutableDictionary,性能最好的是OSSpinLock。

自旋锁的优点:

但是OSSpinLock不安全。

os_unfair_lock

自旋锁已经不在安全,然后苹果又整出来个 os_unfair_lock_t
这个锁解决了优先级反转问题。

    os_unfair_lock_t unfairLock;
    unfairLock = &(OS_UNFAIR_LOCK_INIT);
    os_unfair_lock_lock(unfairLock);
    os_unfair_lock_unlock(unfairLock);

结论

所以如果同一线程优先级可以用,OSSpinLock。如果不在同一线程优先级的话在iOS 10用os_unfair_lock

上一篇 下一篇

猜你喜欢

热点阅读