自旋锁 与 互斥锁
自旋锁 (spin lock)
: 如果一个线程需要获取自旋锁,该锁已经被其他线程占用,该线程不会被挂起,而是不断消耗CPU时间,一直试图获取自旋锁。
-
互斥锁 (mutex)
:如果一个线程无法获取互斥量,该线程会被直接挂起,不再小号CPU时间,当其他线程释放互斥量后,操作系统会激活被挂起的线程。
使用场景:
多核处理器
:如果预计线程等待锁的时间比较短,短到比线程两次切换上下文的时间还要少的情况下,自旋锁是更好的选择。如果时间比较长,则互斥锁是比较好的选择。
-
单核处理器
:一般不建议使用自旋锁。因为在同一时间片内只有一个线程处在运行状态,如果线程a已经获取到锁,但是此时时间片轮到线程b执行,但是线程b获取锁,只能等待解锁,但是因为自己不挂起,所以线程a无法进入运行状态,只能等到线程b的时间片消耗完,线程a才有机会被OS调度执行。此时使用自旋锁的代价很高。
如果加锁的代码经常被调用,但是竞争发生的比较少时,应该优先考虑使用自旋锁,毕竟互斥锁的切换上下文的开销比较大。
性能对比
iOS中的锁包括:
- @synchronized
- NSLock
- NSCondition
- NSConditionLock
- NSRecursiveLock
- pthread_mutex_t
- dispatch_semaphore_t
- OSSpinLock
做的测试是对每种锁进行100万次的加锁解锁操作,对比时间,使用的iPhone6
的iOS10.1.1
的设备,测试结果如下:
从对比可以看出,性能最优的是OSSpinLock
,最差的是@synchronized
,下面是我制作的各种锁的性能对比,不同的系统和设备的数值可能会有差异:
<h3 align = "center">测试代码</h3>
<a name="fenced-code-block">@synchronized()</a>
CFTimeInterval timeBefore;
CFTimeInterval timeCurrent;
NSUInteger i;
NSUInteger count = 1000*10000;//执行一千万次
//@synchronized
id obj = [[NSObject alloc]init];;
timeBefore = CFAbsoluteTimeGetCurrent();
for(i=0; i<count; i++){
@synchronized(obj){
}
}
timeCurrent = CFAbsoluteTimeGetCurrent();
printf("@synchronized : %f\n", timeCurrent-timeBefore);
<a name="fenced-code-block">NSLock</a>
NSLock *lock = [[NSLock alloc]init];
timeBefore = CFAbsoluteTimeGetCurrent();
for(i=0; i<count; i++){
[lock lock];
[lock unlock];
}
timeCurrent = CFAbsoluteTimeGetCurrent();
printf("NSLock : %f\n", timeCurrent-timeBefore);
<a name="fenced-code-block">NSCondition</a>
NSCondition *condition = [[NSCondition alloc]init];
timeBefore = CFAbsoluteTimeGetCurrent();
for(i=0; i<count; i++){
[condition lock];
[condition unlock];
}
timeCurrent = CFAbsoluteTimeGetCurrent();
printf("NSCondition : %f\n", timeCurrent-timeBefore);
<a name="fenced-code-block">NSConditionLock</a>
NSConditionLock *conditionLock = [[NSConditionLock alloc]init];
timeBefore = CFAbsoluteTimeGetCurrent();
for(i=0; i<count; i++){
[conditionLock lock];
[conditionLock unlock];
}
timeCurrent = CFAbsoluteTimeGetCurrent();
printf("NSConditionLock : %f\n", timeCurrent-timeBefore);
<a name="fenced-code-block">NSRecursiveLock</a>
NSRecursiveLock *recursiveLock = [[NSRecursiveLock alloc]init];
timeBefore = CFAbsoluteTimeGetCurrent();
for(i=0; i<count; i++){
[recursiveLock lock];
[recursiveLock unlock];
}
timeCurrent = CFAbsoluteTimeGetCurrent();
printf("NSRecursiveLock : %f\n", timeCurrent-timeBefore);
<a name="fenced-code-block">pthread_mutex_t</a>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
timeBefore = CFAbsoluteTimeGetCurrent();
for(i=0; i<count; i++){
pthread_mutex_lock(&mutex);
pthread_mutex_unlock(&mutex);
}
timeCurrent = CFAbsoluteTimeGetCurrent();
printf("pthread_mutex : %f\n", timeCurrent-timeBefore);
<a name="fenced-code-block">dispatch_semaphore_t</a>
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
timeBefore = CFAbsoluteTimeGetCurrent();
for(i=0; i<count; i++){
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_semaphore_signal(semaphore);
}
timeCurrent = CFAbsoluteTimeGetCurrent();
printf("dispatch_semaphore : %f\n", timeCurrent-timeBefore);
<a name="fenced-code-block">OSSpinLock</a>
OSSpinLock spinlock = OS_SPINLOCK_INIT;
timeBefore = CFAbsoluteTimeGetCurrent();
for(i=0; i<count; i++){
OSSpinLockLock(&spinlock);
OSSpinLockUnlock(&spinlock);
}
timeCurrent = CFAbsoluteTimeGetCurrent();
printf("OSSpinLock : %f\n", timeCurrent-timeBefore);
网友评论