锁总结
1、自旋锁
线程反复检查锁变量是否可用,由于线程在这一过程中保持执行,因此是一种忙等待。一旦获取了自旋锁,线程会一直保持该锁,直至显示释放自旋锁,自旋锁避免了进程上下文的调度开销。因此对于线程只会阻塞很短时间的场合是有效的,而atomic 就是通过在 setter、getter 方法中添加自旋锁来实现线程安全的。
2、互斥锁
互斥锁时用于多线程编程中,防止多条线程同时对统一公共资源进行读写访问的锁。通过将代码切成一个个的临界区而达成,就像加入一个线程在执行还没解锁,那当前线程就休息一会。自旋锁是忙等,互斥锁时获取不到锁就休眠,其他线程解锁后在唤醒继续执行。自旋锁效率更高,但是性能消耗也大。
NSLock
pthread_mutex
@synchronized
3、读写锁
读写锁是一种特殊的自旋锁,他把共享资源的访问者划分成读者和写者,读者只对公共资源进行访问,写者则需要对公共资源进行写操作
这种锁对于自旋锁而言,能提高并发性,隐藏在多处理系统中,他允许同时多个读者访问共享资源,最大可能的读者数为实际的逻辑CPU数,写者是排他性的,一个读写锁同时只能有一个写者或多个读者,但不能同时有读者 和 写者,在读写锁保持期间也是抢占失效的。
如果读写锁当前没有读者,也没有写者,那么写者可以立刻获得读写锁,否者他必须自选在那里,直到没有任何写者或读者。如果读写锁没有写者,那么读者可以立即获得该读写锁,否者读者必须自选在那里,直到写者释放该读写锁
一次只能有一个线程可以占有写模式的读写锁,但是可以有多个线程同时占有读模式的读写锁。
(1)、当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞
(2)、当读写锁在读加锁状态时,所有试图以读模式对它进行加锁的线程都可以得到访问权,但是如果线程希望以写模式对此锁进行加锁,它必须等d所有的线程释放锁。
(3)、通常当读写锁处于读模式锁住状态时,如果有另外线程试图以写模式加锁,读写锁通常会阻塞随后的读模式锁请求,这样可以避免读模式锁长时间占用,而等待的写模式锁请求长时间阻塞。
(4)、读写锁适合于对数据结构的读次数比写次数多得多的情况。因为,读模式锁定时可以共享,以写模式锁住时意味着独占,所以读写锁又叫 共享 - 独占锁
读写锁实现
#pragma mark - 读数据
- (id)lg_objectForKey:(NSString *)key{
__block id obj;
// 同步读取指定数据:
dispatch_sync(self.concurrent_queue, ^{
obj = [self.dataCenterDic objectForKey:key];
});
return obj;
}
#pragma mark - 写数据
- (void)lg_setObject:(id)obj forKey:(NSString *)key{
// 异步栅栏调用设置数据:
dispatch_barrier_async(self.concurrent_queue, ^{
[self.dataCenterDic setObject:obj forKey:key];
});
}
我们可以创建一个并发队列,对于读操作,我们可以用同步函数进行处理,对于写操作我们可以用异步栅栏函数这操作,这样就简单实现了一个读写锁
互斥锁里 tls解释