天天看点

不同锁的性能比较

1、OSSpinLock(自旋锁) High-level lock

OSSpinLock叫做”自旋锁”,等待锁的线程会处于忙等(busy-wait)状态,一直占用着CPU资源

目前已经不再安全,可能会出现优先级反转问题

如果等待锁的线程优先级较高,它会一直占用着CPU资源,优先级低的线程就无法释放锁

需要导入头文件#import <libkern/OSAtomic.h>

#import <libkern/OSAtomic.h>

@interface OSSpinLockDemo()
@property (assign, nonatomic) OSSpinLock lock;
@end

@implementation OSSpinLockDemo

- (void)viewDidLoad {
    [super viewDidLoad];

     // 初始化锁
    self.lock = OS_SPINLOCK_INIT;

    //加锁
    OSSpinLockLock(&_lock);
    
     //尝试加锁,如果不需要等待就加锁返回ture,如果需要等待就不加锁返回false
    //bool result = OSSpinLockTry(&_lock);

    [self testSpinLock];

    //解锁
    OSSpinLockUnlock(&_lock);
}
           

2、os_unfair_lock(互斥锁) Low-level lock

os_unfair_lock用于取代不安全的OSSpinLock ,从iOS10开始才支持

从底层调用看,等待os_unfair_lock锁的线程会处于休眠状态,并非忙等

需要导入头文件#import <os/lock.h>

#import <os/lock.h>

@interface OSUnfairLockDemo()
@property (assign, nonatomic) os_unfair_lock lock;
@end

@implementation OSUnfairLockDemo

- (void)viewDidLoad {
    [super viewDidLoad];

     // 初始化锁
    self.lock = OS_UNFAIR_LOCK_INIT;

    //加锁
    os_unfair_lock_lock(&_lock);
    
     //尝试加锁,如果不需要等待就加锁返回ture,如果需要等待就不加锁返回false
    //bool result = os_unfair_lock_trylock(&_lock);

    [self testUnfairLock];

    //解锁
    os_unfair_lock_unlock(&_lock);
}
           

 ibireme 大神 《不再安全的 OSSpinLock》 这篇文章表示OSSpinLock不再安全,新版 iOS 中,系统维护了 5 个不同的线程优先级/QoS: background,utility,default,user-initiated,user-interactive。高优先级线程始终会在低优先级线程前执行,一个线程不会受到比它更低优先级线程的干扰。这种线程调度算法会产生潜在的优先级反转问题,从而破坏了 spinlock。

3、pthread_mutex -需要销毁

#import <pthread.h>

/*

/*
 * Mutex type attributes
 */
#define PTHREAD_MUTEX_NORMAL		0
#define PTHREAD_MUTEX_ERRORCHECK	1
#define PTHREAD_MUTEX_RECURSIVE		2
#define PTHREAD_MUTEX_DEFAULT		PTHREAD_MUTEX_NORMAL


*/
@interface MutexDemo()
@property (assign, nonatomic) pthread_mutex_t mutex;
@end

@implementation MutexDemo

- (void)viewDidLoad {
    [super viewDidLoad];

    // 静态初始化
    //pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    
    // 初始化属性
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
    // 初始化锁
    pthread_mutex_init(_mutex, &attr);

    //pthread_mutex_init(_mutex, NULL);//传空也是默认PTHREAD_MUTEX_DEFAULT

    // 销毁属性
    pthread_mutexattr_destroy(&attr);

    pthread_mutex_lock(&_mutex);
    
    [self testMutex];
    
    pthread_mutex_unlock(&_mutex);
}

- (void)testMutex
{
    NSLog(@"%s", __func__);
}

- (void)dealloc
{
    pthread_mutex_destroy(&_mutex);
}
           
#import <pthread.h>

@interface MutexDemo()
@property (assign, nonatomic) pthread_mutex_t mutex;
@end

@implementation MutexDemo

- (void)viewDidLoad {
    [super viewDidLoad];

    // 初始化属性
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    // 递归锁:允许同一个线程对一把锁进行重复加锁
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    // 初始化锁
    pthread_mutex_init(_mutex, &attr);

    // 销毁属性
    pthread_mutexattr_destroy(&attr);
 
    [self otherTest];
}

- (void)testMutex
{
    NSLog(@"%s", __func__);
}

- (void)otherTest
{
    pthread_mutex_lock(&_mutex);
    
    NSLog(@"%s", __func__);
    
    static int count = 0;
    if (count < 10) {
        count++;
        [self otherTest];
    }
    
    pthread_mutex_unlock(&_mutex);
}

- (void)dealloc
{
    pthread_mutex_destroy(&_mutex);
}
           
#import <pthread.h>

@interface MutexDemo()
@property (assign, nonatomic) pthread_mutex_t mutex;
@property (assign, nonatomic) pthread_cond_t cond;
@property (strong, nonatomic) NSMutableArray *data;
@end

@implementation MutexDemo

- (void)viewDidLoad {
    [super viewDidLoad];
    // 初始化属性
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);//条件锁
    // 初始化锁
    pthread_mutex_init(&_mutex, &attr);
    // 销毁属性
    pthread_mutexattr_destroy(&attr);
        
    // 初始化条件
    pthread_cond_init(&_cond, NULL);
        
    self.data = [NSMutableArray array];
    [self otherTest];
}

- (void)otherTest
{
    [[[NSThread alloc] initWithTarget:self selector:@selector(__remove) object:nil] start];
    
    [[[NSThread alloc] initWithTarget:self selector:@selector(__add) object:nil] start];
}

// 生产者-消费者模式

// 线程1
// 删除数组中的元素
- (void)__remove
{
    pthread_mutex_lock(&_mutex);
    NSLog(@"__remove - begin");
    
    if (self.data.count == 0) {
        // 等待
        pthread_cond_wait(&_cond, &_mutex);
    }
    
    [self.data removeLastObject];
    NSLog(@"删除了元素");
    
    pthread_mutex_unlock(&_mutex);
}

// 线程2
// 往数组中添加元素
- (void)__add
{
    pthread_mutex_lock(&_mutex);
    
    sleep(1);
    
    [self.data addObject:@"Test"];
    NSLog(@"添加了元素");
    
    // 信号
    pthread_cond_signal(&_cond);
    // 广播
//    pthread_cond_broadcast(&_cond);
    
    pthread_mutex_unlock(&_mutex);
}

- (void)dealloc
{
    pthread_mutex_destroy(&_mutex);
    pthread_cond_destroy(&_cond);
}
           

4、NSLock

NSLock是对mutex普通锁的封装

不同锁的性能比较

5、NSRecursiveLock

NSRecursiveLock也是对mutex递归锁的封装,API跟NSLock基本一致

6、NSCondition

NSCondition是对mutex和cond的封装

@interface NSConditionDemo()
@property (strong, nonatomic) NSCondition *condition;
@property (strong, nonatomic) NSMutableArray *data;
@end

@implementation NSConditionDemo

- (void)viewDidLoad {
    [super viewDidLoad];

     self.condition = [[NSCondition alloc] init];
     self.data = [NSMutableArray array];
    [self otherTest];
}

- (void)otherTest
{
    [[[NSThread alloc] initWithTarget:self selector:@selector(__remove) object:nil] start];
    
    [[[NSThread alloc] initWithTarget:self selector:@selector(__add) object:nil] start];
}


// 线程1
// 删除数组中的元素
- (void)__remove
{
    [self.condition lock];
    NSLog(@"__remove - begin");
    
    if (self.data.count == 0) {
        // 等待
        [self.condition wait];
    }
    
    [self.data removeLastObject];
    NSLog(@"删除了元素");
    
    [self.condition unlock];
}

// 线程2
// 往数组中添加元素
- (void)__add
{
    [self.condition lock];
    
    sleep(1);
    
    [self.data addObject:@"Test"];
    NSLog(@"添加了元素");
    
    // 信号
    [self.condition signal];
    
    sleep(2);
    
    [self.condition unlock];
}
           

7、NSConditionLock

NSConditionLock是对NSCondition的进一步封装,可以设置具体的条件值,默认为0;

@interface NSConditionLockDemo()
@property (strong, nonatomic) NSConditionLock *conditionLock;
@end

@implementation NSConditionLockDemo

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.conditionLock = [[NSConditionLock alloc] initWithCondition:1];

    [self otherTest];
}

- (void)otherTest
{
    [[[NSThread alloc] initWithTarget:self selector:@selector(__one) object:nil] start];
    
    [[[NSThread alloc] initWithTarget:self selector:@selector(__two) object:nil] start];
    
    [[[NSThread alloc] initWithTarget:self selector:@selector(__three) object:nil] start];
}

- (void)__one
{
    [self.conditionLock lock];//不管条件值,直接加锁
    
    NSLog(@"__one");
    sleep(1);
    
    [self.conditionLock unlockWithCondition:2];
}

- (void)__two
{
    [self.conditionLock lockWhenCondition:2];//必须满足条件才能加锁
    
    NSLog(@"__two");
    sleep(1);
    
    [self.conditionLock unlockWithCondition:3];
}

- (void)__three
{
    [self.conditionLock lockWhenCondition:3];
    
    NSLog(@"__three");
    
    [self.conditionLock unlock];
}
           

8、dispatch_semaphore

semaphore叫做”信号量”

信号量的初始值,可以用来控制线程并发访问的最大数量

信号量的初始值为1,代表同时只允许1条线程访问资源,保证线程同步

@interface SemaphoreDemo()
@property (strong, nonatomic) dispatch_semaphore_t semaphore;
@end

@implementation SemaphoreDemo

- (void)viewDidLoad {
    [super viewDidLoad];
     self.semaphore = dispatch_semaphore_create(5);//设置为1则是串行队列,>1为并发
}

- (void)otherTest
{
    for (int i = 0; i < 20; i++) {
        [[[NSThread alloc] initWithTarget:self selector:@selector(test) object:nil] start];
    }
}

- (void)test
{
    // 如果信号量的值 > 0,就让信号量的值减1,然后继续往下执行代码
    // 如果信号量的值 <= 0,就会休眠等待,直到信号量的值变成>0,就让信号量的值减1,然后继续往下执行代码
    dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
    
    sleep(2);
    NSLog(@"test - %@", [NSThread currentThread]);
    
    // 让信号量的值+1
    dispatch_semaphore_signal(self.semaphore);
}
           

9、synchronized(递归锁)

@synchronized是对mutex递归锁的封装,在xcode编写的时候不会有提示,性能比较低。

@synchronized(obj)内部会生成obj对应的递归锁,然后进行加锁、解锁操作

/*
typedef struct alignas(CacheLineSize) SyncData {
    struct SyncData* nextData;
    DisguisedPtr<objc_object> object;
    int32_t threadCount;  // number of THREADS using this block
    recursive_mutex_t mutex;
} SyncData;

*/
//底层实现 objc_sync.mm  objc_sync_enter objc_sync_exit  syncData  里面是哈希表查找 c++结构
@synchronized([self class]) {
 
     [self otherTest];
}
           

性能从高到低排序:os_unfair_lock >OSSpinLock>dispatch_semaphore>pthread_mutex>NSLock>NSCondition>pthread_mutex(recursive)>NSConditionLock>@synchronized(在加锁和解锁的代码上算出所用的时间差)OSSpinLock,dispatch_semaphore的性能远远优于其他的锁,但是OSSpinLock由于优先级反转的问题,苹果在iOS10的时候推出了os_unfair_lock来替代,而且性能不减当年,但是要在iOS10之后才能用(虽然自旋锁的性能优于互斥锁),可以看出@synchronize和NSConditionLock明显性能最差,如果项目中对性能特别敏感,建议使用dispatch_semaphore,如果基于方便的话就用@synchronize也可以,影响不大。

继续阅读