iOS多线程——锁
在开发中,多线程编程是必不可少的,多线程的线程安全也是要考虑的,可能最有印象的应该还是atomic属性吧,其次就是GCD的dispatch_semaphore。于是就总结了一下,iOS开发中的线程安全措施。大致有如下几种:
- atomic属性
- @synchronize(对象)
- NSLock 需要提一下,lock、unlock方法必须在一个线程调用,这里说的很清楚
- NSRecursiveLock 递归锁,能在同一个线程多次请求不会死锁
- NSCondition
- NSConditionLock
- OSSpinLock 自旋锁,被弃用了,因为存在优先级反转问题,苹果已经弃用,并用os_unfair_lock作为替代。需要引入头文件 #impot< libkern/OSAtomic.h>
os_unfair_lock 不公平的锁,就是解决优先级反转问题。 需要引入头文件 #import < os/lock.h>
pthread_mutex 创建需由pthread_attr_t参数,如果参数attr为空,则使用默认的互斥锁属性,默认属性为快速互斥锁 。互斥锁的属性在创建锁的时候指定,不同的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不同。(#define PTHREAD_MUTEX_NORMAL
#define PTHREAD_MUTEX_ERRORCHECK
#define PTHREAD_MUTEX_RECURSIVE 三种属性)至于不同属性的性能,都是一家的,在这里就不比较了- dispatch_semaphore
既然有这么多的实现方式,当然要一较高下,选择自己喜欢的方式,于是写了下面的测试代码比较性能:
NSMutableArray *timeArr = [NSMutableArray array];
CFTimeInterval start,end,cost;
NSInteger count = 100000;
NSArray *nameArr = @[@"OSSpinLock",@"NSLock",@"dispatch_semaphore",@"pthread_mutex",@"NSCondition",@"NSConditionLock",@"NSRecursiveLock",@"@synchronized",@"os_unfair_lock"];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
{
OSSpinLock lock = OS_SPINLOCK_INIT;
start = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < count; i++) {
OSSpinLockLock(&lock);
OSSpinLockUnlock(&lock);
}
end = CFAbsoluteTimeGetCurrent();
cost = end - start;
[timeArr addObject:@(cost)];
}
#pragma clang pop
{
NSLock *lock = [NSLock new];
start = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < count; i++) {
[lock lock];
[lock unlock];
}
end = CFAbsoluteTimeGetCurrent();
cost = end - start;
[timeArr addObject:@(cost)];
}
{
dispatch_semaphore_t lock = dispatch_semaphore_create(1);
start = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < count; i++) {
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
dispatch_semaphore_signal(lock);
}
end = CFAbsoluteTimeGetCurrent();
cost = end - start;
[timeArr addObject:@(cost)];
}
{
pthread_mutex_t lock;
pthread_mutex_init(&lock, NULL);
start = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < count; i++) {
pthread_mutex_lock(&lock);
pthread_mutex_unlock(&lock);
}
end = CFAbsoluteTimeGetCurrent();
cost = end - start;
[timeArr addObject:@(cost)];
}
{
NSCondition *lock = [NSCondition new];
start = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < count; i++) {
[lock lock];
[lock unlock];
}
end = CFAbsoluteTimeGetCurrent();
cost = end - start;
[timeArr addObject:@(cost)];
}
{
NSConditionLock *lock = [[NSConditionLock alloc] initWithCondition:1];
start = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < count; i++) {
[lock lock];
[lock unlock];
}
end = CFAbsoluteTimeGetCurrent();
cost = end - start;
[timeArr addObject:@(cost)];
}
{
NSRecursiveLock *lock = [NSRecursiveLock new];
start = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < count; i++) {
[lock lock];
[lock unlock];
}
end = CFAbsoluteTimeGetCurrent();
cost = end - start;
[timeArr addObject:@(cost)];
}
{
NSObject *lock = [NSObject new];
start = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < count; i++) {
@synchronized(lock) {}
}
end = CFAbsoluteTimeGetCurrent();
cost = end - start;
[timeArr addObject:@(cost)];
}
{
os_unfair_lock_t unfairLock;
unfairLock = &(OS_UNFAIR_LOCK_INIT);
start = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < count; i++) {
os_unfair_lock_lock(unfairLock);
os_unfair_lock_unlock(unfairLock);
}
end = CFAbsoluteTimeGetCurrent();
cost = end - start;
[timeArr addObject:@(cost)];
}
for (int i = 0; i < timeArr.count; i++) {
NSLog(@"------%@------%@\n",timeArr[i],nameArr[i]);
}
最后打印结果如下:
------0.0009900331497192383------OSSpinLock
------0.00348198413848877------NSLock
------0.001325011253356934------dispatch_semaphore
------0.002358973026275635------pthread_mutex
------0.003148019313812256------NSCondition
------0.01061898469924927------NSConditionLock
------0.00425797700881958------NSRecursiveLock
------0.0124550461769104------@synchronized
------0.00145798921585083------os_unfair_lock
可以看出要是没有优先级反转的问题的话,osspinlock占有绝对,其次就是dispatch_semaphore,dispatch_semaphore和os_unfair_lock差距很小,其次就是pthread_mutex。其实在测试的时候呢,性能和次数是有关系的,即是说这几种锁在不同的情形下会发挥最好性能,次数量大的时候呢,性能排名就如上面一样。所以在项目中使用的话,就根据项目情况选择即可。
好吧!就到这里,对iOS锁也算有了一定的了解。 还是那句话,如您发现任何错误,欢迎留言指正~