自旋锁:
是一种用于保护多线程共享资源的锁,与一般互斥锁(mutex)不同之处在于当自旋锁尝试获取锁时以忙等 待(busy waiting)的形式不断地循环检查锁是否可用。当上一个线程的任务没有执行完毕的时候(被锁住), 那么下一个线程会一直等待(不会睡眠),当上一个线程的任务执行完毕,下一个线程会立即执行。
在多 CPU 的环境中,对持有锁较短的程序来说,使用自旋锁代替一般的互斥锁往往能够提高程序的性能。
互斥锁:
当上一个线程的任务没有执行完毕的时候(被锁住),那么下一个线程会进入睡眠状态等待任务执行完毕, 当上一个线程的任务执行完毕,下一个线程会自动唤醒然后执行任务。
总结:
自旋锁会忙等: 所谓忙等,即在访问被锁资源时,调用者线程不会休眠,而是不停循环在那里,直到被锁 资源释放锁。
互斥锁会休眠: 所谓休眠,即在访问被锁资源时,调用者线程会休眠,此时 cpu 可以调度其他线程工 作。直到被锁资源释放锁。此时会唤醒休眠线程。
优缺点:
自旋锁的优点在于,因为自旋锁不会引起调用者睡眠,所以不会进行线程调度,CPU 时间片轮转等耗时操 作。所有如果能在很短的时间内获得锁,自旋锁的效率远高于互斥锁。
缺点在于,自旋锁一直占用 CPU,他在未获得锁的情况下,一直运行--自旋,所以占用着 CPU,如果不 能在很短的时 间内获得锁,这无疑会使 CPU 效率降低。自旋锁不能实现递归调用。
自旋锁:atomic、OSSpinLock、dispatch_semaphore_t
互斥锁:pthread_mutex、@ synchronized、NSLock、NSConditionLock 、NSCondition、NSRecursiveLock
锁的归类
条件锁:就是条件变量,当进程的某些资源要求不满足时就进入休眠,也就
是锁住了。当资源被分配到了,条件锁打开,进程继续运行
NSCondition
NSConditionLock
递归锁:就是同一个线程可以加锁N次而不会引发死锁
NSRecursiveLock
pthread_mutex(recursive)
信号量(semaphore):是一种更高级的同步机制,互斥锁可以说是
semaphore在仅取值0/1时的特例。信号量可以有更多的取值空间,用来实
现更加复杂的同步,而不单单是线程间互斥。
dispatch_semaphore
其实基本的锁就包括了三类 自旋锁 互斥锁 读写锁,
其他的比如条件锁,递归锁,信号量都是上层的封装和实现!
读写锁
读写锁适合于对数据结构的读次数比写次数多得多的情况. 因为, 读模式锁定时可以共享, 以写模式锁住时意味
着独占, 所以读写锁又叫共享-独占锁.
include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
成功则返回0, 出错则返回错误编号.
同互斥量以上, 在释放读写锁占用的内存之前, 需要先通过pthread_rwlock_destroy对读写锁进行清理工作, 释
放由init分配的资源.
include <pthread.h>
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
成功则返回0, 出错则返回错误编号.
这3个函数分别实现获取读锁, 获取写锁和释放锁的操作. 获取锁的两个函数是阻塞操作, 同样, 非阻塞的函数为:
include <pthread.h>
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
成功则返回0, 出错则返回错误编号.
非阻塞的获取锁操作, 如果可以获取则返回0, 否则返回错误的EBUSY
#define KCLog(format, ...) printf("%s\n", [[NSString stringWithFormat:format, ## __VA_ARGS__] UTF8String]);
#import "ViewController.h"
#import <libkern/OSAtomic.h>
#import <pthread/pthread.h>
#import <os/lock.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
int kc_runTimes = 100000;
/** OSSpinLock 性能 */
{
OSSpinLock kc_spinlock = OS_SPINLOCK_INIT;
double_t kc_beginTime = CFAbsoluteTimeGetCurrent();
for (int i=0 ; i < kc_runTimes; i++) {
OSSpinLockLock(&kc_spinlock); //解锁
OSSpinLockUnlock(&kc_spinlock);
}
double_t kc_endTime = CFAbsoluteTimeGetCurrent() ;
KCLog(@"OSSpinLock: %f ms",(kc_endTime - kc_beginTime)*1000);
}
/** dispatch_semaphore_t 性能 */
{
dispatch_semaphore_t kc_sem = dispatch_semaphore_create(1);
double_t kc_beginTime = CFAbsoluteTimeGetCurrent();
for (int i=0 ; i < kc_runTimes; i++) {
dispatch_semaphore_wait(kc_sem, DISPATCH_TIME_FOREVER);
dispatch_semaphore_signal(kc_sem);
}
double_t kc_endTime = CFAbsoluteTimeGetCurrent() ;
KCLog(@"dispatch_semaphore_t: %f ms",(kc_endTime - kc_beginTime)*1000);
}
/** os_unfair_lock_lock 性能 */
{
os_unfair_lock kc_unfairlock = OS_UNFAIR_LOCK_INIT;
double_t kc_beginTime = CFAbsoluteTimeGetCurrent();
for (int i=0 ; i < kc_runTimes; i++) {
os_unfair_lock_lock(&kc_unfairlock);
os_unfair_lock_unlock(&kc_unfairlock);
}
double_t kc_endTime = CFAbsoluteTimeGetCurrent() ;
KCLog(@"os_unfair_lock_lock: %f ms",(kc_endTime - kc_beginTime)*1000);
}
/** pthread_mutex_t 性能 */
{
pthread_mutex_t kc_metext = PTHREAD_MUTEX_INITIALIZER;
double_t kc_beginTime = CFAbsoluteTimeGetCurrent();
for (int i=0 ; i < kc_runTimes; i++) {
pthread_mutex_lock(&kc_metext);
pthread_mutex_unlock(&kc_metext);
}
double_t kc_endTime = CFAbsoluteTimeGetCurrent() ;
KCLog(@"pthread_mutex_t: %f ms",(kc_endTime - kc_beginTime)*1000);
}
/** NSlock 性能 */
{
NSLock *kc_lock = [NSLock new];
double_t kc_beginTime = CFAbsoluteTimeGetCurrent();
for (int i=0 ; i < kc_runTimes; i++) {
[kc_lock lock];
[kc_lock unlock];
}
double_t kc_endTime = CFAbsoluteTimeGetCurrent() ;
KCLog(@"NSlock: %f ms",(kc_endTime - kc_beginTime)*1000);
}
/** NSCondition 性能 */
{
NSCondition *kc_condition = [NSCondition new];
double_t kc_beginTime = CFAbsoluteTimeGetCurrent();
for (int i=0 ; i < kc_runTimes; i++) {
[kc_condition lock];
[kc_condition unlock];
}
double_t kc_endTime = CFAbsoluteTimeGetCurrent() ;
KCLog(@"NSCondition: %f ms",(kc_endTime - kc_beginTime)*1000);
}
/** PTHREAD_MUTEX_RECURSIVE 性能 */
{
pthread_mutex_t kc_metext_recurive;
pthread_mutexattr_t attr;
pthread_mutexattr_init (&attr);
pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init (&kc_metext_recurive, &attr);
double_t kc_beginTime = CFAbsoluteTimeGetCurrent();
for (int i=0 ; i < kc_runTimes; i++) {
pthread_mutex_lock(&kc_metext_recurive);
pthread_mutex_unlock(&kc_metext_recurive);
}
double_t kc_endTime = CFAbsoluteTimeGetCurrent() ;
KCLog(@"PTHREAD_MUTEX_RECURSIVE: %f ms",(kc_endTime - kc_beginTime)*1000);
}
/** NSRecursiveLock 性能 */
{
NSRecursiveLock *kc_recursiveLock = [NSRecursiveLock new];
double_t kc_beginTime = CFAbsoluteTimeGetCurrent();
for (int i=0 ; i < kc_runTimes; i++) {
[kc_recursiveLock lock];
[kc_recursiveLock unlock];
}
double_t kc_endTime = CFAbsoluteTimeGetCurrent() ;
KCLog(@"NSRecursiveLock: %f ms",(kc_endTime - kc_beginTime)*1000);
}
/** NSConditionLock 性能 */
{
NSConditionLock *kc_conditionLock = [NSConditionLock new];
double_t kc_beginTime = CFAbsoluteTimeGetCurrent();
for (int i=0 ; i < kc_runTimes; i++) {
[kc_conditionLock lock];
[kc_conditionLock unlock];
}
double_t kc_endTime = CFAbsoluteTimeGetCurrent() ;
KCLog(@"NSConditionLock: %f ms",(kc_endTime - kc_beginTime)*1000);
}
/** @synchronized 性能 */
{
double_t kc_beginTime = CFAbsoluteTimeGetCurrent();
for (int i=0 ; i < kc_runTimes; i++) {
@synchronized(self) {}
}
double_t kc_endTime = CFAbsoluteTimeGetCurrent() ;
KCLog(@"@synchronized: %f ms",(kc_endTime - kc_beginTime)*1000);
}
}
@end
OSSpinLock: 0.718951 ms
dispatch_semaphore_t: 1.291990 ms
os_unfair_lock_lock: 1.291037 ms
pthread_mutex_t: 1.830935 ms
NSlock: 2.039075 ms
NSCondition: 2.015948 ms
PTHREAD_MUTEX_RECURSIVE: 3.154993 ms
NSRecursiveLock: 3.970027 ms
NSConditionLock: 5.892992 ms
@synchronized: 6.525993 ms