我们在使用多线程的时候,同一时刻可能会有多个线程访问同一内存的内容,这样就很容易引发数据混乱(数据安全)的问题。为了减少或者避免这种问题的出现,我们需要使用锁来保证统一时刻只有一个线程访问这一块内存。锁可以让数据的访问更安全。
我们常见的锁包括OSSpinLock
、dispatch_semaphore_t
、os_unfair_lock
、pthread_mutex_t
、NSlock
、NSCondition
、pthread_mutex_t(recursive)
、NSRecursiveLock
、NSConditionLock
、@synchronized
等10来种。
按照特性划分,锁可以分为自旋锁
和互斥锁
:
1.自旋锁:线程反复检查锁变量是否可用。由于线程在这一过程中保持执行,因此是一种忙等待。一旦获取了自旋锁,线程会一直保持该锁,甚至显示释放自旋锁。自旋锁避免了进程上下文调度的开销,因此对于线程只会阻塞很短时间的场合是有效的。
2.互斥锁:是一种利用于多线程编程中,防止两条线程同时对统一资源进行读写的机制。该目的是通过将代码切片成一个一个临时区二达成的。属于互斥锁的有NSlock
、pthread_mutex_t
、@synchronized
。
那么它们各自的性能优势什么样的呢?我们来做一个简单的测试,测试代码如下:
- (void)test{
int loop = 100000;
{
OSSpinLock lock = OS_SPINLOCK_INIT;
double_t start = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < loop; i++){
OSSpinLockLock(&lock);
OSSpinLockUnlock(&lock);
}
double_t end = CFAbsoluteTimeGetCurrent();
NSLog(@"OSSpinLock:%f", (end - start)*1000);
}
{
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
double_t start = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < loop; i++){
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_semaphore_signal(semaphore);
}
double_t end = CFAbsoluteTimeGetCurrent();
NSLog(@"dispatch_semaphore_t:%f", (end - start)*1000);
}
{
os_unfair_lock unfair = OS_UNFAIR_LOCK_INIT;
double_t start = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < loop; i++){
os_unfair_lock_lock(&unfair);
os_unfair_lock_unlock(&unfair);
}
double_t end = CFAbsoluteTimeGetCurrent();
NSLog(@"os_unfair_lock:%f", (end - start)*1000);
}
{
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
double_t start = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < loop; i++){
pthread_mutex_lock(&mutex);
pthread_mutex_unlock(&mutex);
}
double_t end = CFAbsoluteTimeGetCurrent();
NSLog(@"pthread_mutex_t:%f", (end - start)*1000);
}
{
pthread_mutex_t recurive;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&recurive, &attr);
double_t start = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < loop; i++){
pthread_mutex_lock(&recurive);
pthread_mutex_unlock(&recurive);
}
double_t end = CFAbsoluteTimeGetCurrent();
NSLog(@"pthread_mutex_t(recurive):%f", (end - start)*1000);
}
{
NSLock *lock = [NSLock new];
double_t start = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < loop; i++){
[lock lock];
[lock unlock];
}
double_t end = CFAbsoluteTimeGetCurrent();
NSLog(@"NSLock:%f", (end - start)*1000);
}
{
NSRecursiveLock *recursiveLock = [NSRecursiveLock new];
double_t start = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < loop; i++){
[recursiveLock lock];
[recursiveLock unlock];
}
double_t end = CFAbsoluteTimeGetCurrent();
NSLog(@"NSRecursiveLock:%f", (end - start)*1000);
}
{
NSCondition *condition = [NSCondition new];
double_t start = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < loop; i++){
[condition lock];
[condition unlock];
}
double_t end = CFAbsoluteTimeGetCurrent();
NSLog(@"NSCondition:%f", (end - start)*1000);
}
{
NSConditionLock *conditionLock = [NSConditionLock new];
double_t start = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < loop; i++){
[conditionLock lock];
[conditionLock unlock];
}
double_t end = CFAbsoluteTimeGetCurrent();
NSLog(@"NSConditionLock:%f", (end - start)*1000);
}
{
double_t start = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < loop; i++){
@synchronized (self) {
}
}
double_t end = CFAbsoluteTimeGetCurrent();
NSLog(@"@synchronized:%f", (end - start)*1000);
}
}
也就是我们尝试加锁解锁10万次,看这个过程耗费的时间(单位:毫秒ms)。
在模拟器上运行时间如下:(单位:毫秒)
在真机上运行时间如下:(单位:毫秒)
真机和模拟器上运行结果基本相近,在真机上@synchronized的表现要比模拟器上号很多,从7.5毫秒提升到2.7毫秒(猜测:@synchronized可能苹果针对arm有专门的优化?)
1.@synchronized
加锁的效果
递归可重用
结构
const NSString *syncKey = (NSString *)&__NSConstantStringImpl__var_folders_ns_73tnh7591jvg16yqm8fn6ykh0000gn_T_NXXcrun_0a2d9a_mi_0;
// @implementation NXXcrun
static void _C_NXXcrun_main(Class self, SEL _cmd) {
{
id _rethrow = 0;
id _sync_obj = (id)syncKey;
objc_sync_enter(_sync_obj);
try {
struct _SYNC_EXIT {
_SYNC_EXIT(id arg) : sync_exit(arg) {}
~_SYNC_EXIT() {objc_sync_exit(sync_exit);}
id sync_exit;
}
_sync_exit(_sync_obj);
} catch (id e) {_rethrow = e;}
{ struct _FIN {
_FIN(id reth) : rethrow(reth) {}
~_FIN() { if (rethrow) objc_exception_throw(rethrow); }
id rethrow;
} _fin_force_rethow(_rethrow);}
}
}
// @end