锁
线程安全是很重要的,所以为了解决线程安全的问题,可以使用加锁的方式解决。但是各种锁有不用的特点,所以使用的时候需要根据场景来确定。
介绍几种iOS中常见的锁的使用方法和性能排比。各自属于什么类型的锁。
自旋锁
用于多线程同步的一种锁,线程反复检查锁变量是否可用。由于线程在这一过程中保持执行,因此是一种忙等待。一旦获取了自旋锁,线程会一直保持该锁,直至显式释放自旋锁。 自旋锁避免了进程上下文的调度开销,因此对于线程只会阻塞很短时间的场合是有效的。
OSSpinLock
// 不再安全的 OSSpinLock 除此dispatch_semaphore 和 pthread_mutex 性能是最高的
OSSpinLock lock = OS_SPINLOCK_INIT;
begin = CACurrentMediaTime();
for (int i = 0; i < count; i++) {
OSSpinLockLock(&lock);
OSSpinLockUnlock(&lock);
}
end = CACurrentMediaTime();
TimeCosts[LockTypeOSSpinLock] += end - begin;
printf("OSSpinLock: %8.2f ms\n", (end - begin) * 1000);
@synchronized
NSObject *lock = [NSObject new];
begin = CACurrentMediaTime();
for (int i = 0; i < count; i++) {
@synchronized(lock) {}
}
end = CACurrentMediaTime();
TimeCosts[LockTypesynchronized] += end - begin;
printf("@synchronized: %8.2f ms\n", (end - begin) * 1000);
互斥锁(Mutex)
是一种用于多线程编程中,防止两条线程同时对同一公共资源(比如全局变量)进行读写的机制。该目的通过将代码切片成一个一个的临界区而达成。
pthread_mutex_t
pthread_mutex_t lock;
pthread_mutex_init(&lock, NULL);
begin = CACurrentMediaTime();
for (int i = 0; i < count; i++) {
pthread_mutex_lock(&lock);
pthread_mutex_unlock(&lock);
}
end = CACurrentMediaTime();
TimeCosts[LockTypepthread_mutex] += end - begin;
pthread_mutex_destroy(&lock);
printf("pthread_mutex: %8.2f ms\n", (end - begin) * 1000);
NSLock
NSLock *lock = [NSLock new];
begin = CACurrentMediaTime();
for (int i = 0; i < count; i++) {
[lock lock];
[lock unlock];
}
end = CACurrentMediaTime();
TimeCosts[LockTypeNSLock] += end - begin;
printf("NSLock: %8.2f ms\n", (end - begin) * 1000);
读写锁
计算机程序的并发控制的一种同步机制,也称“共享-互斥锁”、多读者-单写者锁) 用于解决多线程对公共资源读写问题。读操作可并发重入,写操作是互斥的。 读写锁通常用互斥锁、条件变量、信号量实现。
读写锁一般是自己实现的。
信号量(semaphore)
一种更高级的同步机制,互斥锁可以说是semaphore在仅取值0/1时的特例。信号量可以有更多的取值空间,用来实现更加复杂的同步,而不单单是线程间互斥。
dispatch_semaphore_t
dispatch_semaphore_t lock = dispatch_semaphore_create(2);
begin = CACurrentMediaTime();
for (int i = 0; i < count; i++) {
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
dispatch_semaphore_signal(lock);
}
end = CACurrentMediaTime();
TimeCosts[LockTypedispatch_semaphore] += end - begin;
printf("dispatch_semaphore: %8.2f ms\n", (end - begin) * 1000);
条件锁
就是条件变量,当进程的某些资源要求不满足时就进入休眠,也就是锁住了。当资源被分配到了,条件锁打开,进程继续运行。
NSCondition *lock = [NSCondition new];
begin = CACurrentMediaTime();
for (int i = 0; i < count; i++) {
[lock lock];
[lock unlock];
}
end = CACurrentMediaTime();
TimeCosts[LockTypeNSCondition] += end - begin;
printf("NSCondition: %8.2f ms\n", (end - begin) * 1000);
另外,需要特别说明一下,属性的原子性操作atomic是setter和getter都会加上一个自旋锁的。