一、 NSConditionLock
- NSConditionLock 是对 NSCondition 的进一步封装,可以设置具体的条件值
- 主要用于处理线程间的依赖
#import "NSConditionLockDemo.h"
@interface NSConditionLockDemo ()
@property(nonatomic, strong)NSConditionLock *conditionLock;
@end
@implementation NSConditionLockDemo
- (instancetype)init
{
self = [super init];
if (self) {
self.conditionLock = [[NSConditionLock alloc] initWithCondition:1];
}
return self;
}
- (void)otherTest {
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
[self __three];
});
dispatch_async(queue, ^{
[self __one];
});
dispatch_async(queue, ^{
[self __two];
});
}
- (void)__one {
[self.conditionLock lockWhenCondition:1];
NSLog(@"%s",__func__);
[self.conditionLock unlockWithCondition:2];
}
- (void)__two {
[self.conditionLock lockWhenCondition:2];
NSLog(@"%s",__func__);
[self.conditionLock unlockWithCondition:3];
}
- (void)__three {
[self.conditionLock lockWhenCondition:3];
NSLog(@"%s",__func__);
[self.conditionLock unlockWithCondition:1];
}
@end
- 上述代码就能保证
_one
、 _two
、 _three
这三个任务按顺序执行。
二、 SerialQueue 串行队列
- 线程同步,目的就是让任务一个个执行。所以我们不一定要用锁来实现,我们用串行队列也是可以的
#import "SerialQueueDemo.h"
@interface SerialQueueDemo ()
@property(nonatomic, strong) dispatch_queue_t serialQueue;
@end
@implementation SerialQueueDemo
- (instancetype)init
{
self = [super init];
if (self) {
self.serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (void)__saleTicket {
dispatch_sync(self.serialQueue, ^{
[super __saleTicket];
});
}
@end
三、 semaphore 信号量
- semaphore 叫做
信号量
- 信号量的初始值,可以用来控制线程
并发访问
的最大数量
- 信号量的初始值为 1,代表同时值允许 1 条线程访问资源,保证线程同步
- semaphore 当 value 为 1 时,也可以达到线程同步的效果。
#import "SemaphoreDemo.h"
@interface SemaphoreDemo ()
@property(nonatomic, strong)dispatch_semaphore_t semaphore1;
@property(nonatomic, strong)dispatch_semaphore_t semaphore5;
@end
@implementation SemaphoreDemo
- (instancetype)init
{
self = [super init];
if (self) {
self.semaphore1 = dispatch_semaphore_create(1);
self.semaphore5 = dispatch_semaphore_create(5);
}
return self;
}
- (void)__saleTicket {
dispatch_semaphore_wait(self.semaphore1, DISPATCH_TIME_FOREVER);
[super __saleTicket];
dispatch_semaphore_signal(self.semaphore1);
}
- (void)__test {
dispatch_semaphore_wait(self.semaphore5, DISPATCH_TIME_FOREVER);
sleep(2.0);
NSLog(@"task");
dispatch_semaphore_signal(self.semaphore5);
}
- (void)otherTest {
for (int i = 0; i < 20; i++) {
[[[NSThread alloc] initWithTarget:self selector:@selector(__test) object:nil] start];
}
}
@end
四、 @sychronized
-
@synchronized
是对 mutex递归锁
的封装
- 源码查看: objc4 中的 objc-sync.mm 文件
-
@synchronized(obj)
内部会生成 obj 对应的递归锁,然后进行加锁、解锁操作
- 最大有点:
使用起来最方便
- 最大缺点:
性能最低
#import "SynchronizedDemo.h"
@implementation SynchronizedDemo
- (void)__saleTicket {
@synchronized(self){
[super __saleTicket];
}
}
- (void)__saveMoney {
@synchronized([self class]){
[super __saveMoney];
}
}
- (void)__drawMoney {
@synchronized([self class]){
[super __drawMoney];
}
}
@end
五、 自旋锁和互斥锁比较
1. 什么情况使用自旋锁比较划算?
- 预计线程等待锁的时间很短
- 加锁的代码(临界区)经常被调用,但竞争情况很少发生
- CPU 资源不紧张
- 多核处理器
2. 什么情况使用互斥锁比较划算?
- 预计线程等待锁的时间比较长
- 单核处理器
- 临界区有 IO 操作
- 临界区代码复杂或者循环量大
- 临界区竞争非常激烈
六、atomic
-
atomic
中文意思 原子性
,可以参考源码 objc4
的 objc-accessors.mm
-
atomic
可以用于保证属性 setter、getter 的原子性操作,相当于在 getter、setter 内部添加了线程同步的锁
-
atomic
不可以保证属性的使用过程
是线程安全的
- 相信 iOS 开发我们经常见到
nonatomic
,极少见到 atomic
,因为搭载 iOS 设备通常内存都不大,会频繁读取属性,如果是 atomic,就会进行加锁,影响效率。一般用在 mac 项目中。
七、如何在 iOS 中实现 多读单写
?(两种方案)
- 同一时间,只能 1 个线程进行写的操作
- 同一时间,允许多个线程进行读的操作
- 同一时间,不允许既有写的操作,又有读的操作
1. 使用这个模板代码尝试解决问题?
- (void)otherTest {
for (int i = 0; i < 10; i++) {
[[[NSThread alloc] initWithTarget:self selector:@selector(__read) object:nil] start];
[[[NSThread alloc] initWithTarget:self selector:@selector(__read) object:nil] start];
[[[NSThread alloc] initWithTarget:self selector:@selector(__write) object:nil] start];
}
}
- (void)__read {
NSLog(@"%s", __func__);
}
- (void)__write {
NSLog(@"%s___start", __func__);
sleep(1.0);
NSLog(@"%s___end", __func__);
}
2. 使用垮平台的 pthread_rwlock_t
-
pthread_rwlock_t
等待锁的线程会进入休眠
#import "PthreadRwlockDemo.h"
#import
@interface PthreadRwlockDemo ()
@property(nonatomic, assign)pthread_rwlock_t rwlock;
@end
@implementation PthreadRwlockDemo
- (instancetype)init
{
self = [super init];
if (self) {
pthread_rwlock_init(&_rwlock, NULL);
}
return self;
}
- (void)otherTest {
for (int i = 0; i < 10; i++) {
[[[NSThread alloc] initWithTarget:self selector:@selector(__read) object:nil] start];
[[[NSThread alloc] initWithTarget:self selector:@selector(__read) object:nil] start];
[[[NSThread alloc] initWithTarget:self selector:@selector(__write) object:nil] start];
}
}
- (void)__read {
pthread_rwlock_rdlock(&_rwlock);
NSLog(@"%s", __func__);
pthread_rwlock_unlock(&_rwlock);
}
- (void)__write {
pthread_rwlock_wrlock(&_rwlock);
sleep(1.0);
NSLog(@"%s", __func__);
pthread_rwlock_unlock(&_rwlock);
}
- (void)dealloc {
pthread_rwlock_destroy(&_rwlock);
}
@end
3. 使用 iOS 提供的栅栏函数 dispatch_barrier_async
- 这个函数传入的
并发队列
必须是自己通过 dispatch_queue_create
创建的
- 如果传入的是一个
串行
或者是一个全局并发队列
,那么这个函数便等同于dispatch_async
函数的效果
#import "DispatchBarrierAsyncDemo.h"
@interface DispatchBarrierAsyncDemo ()
@property(nonatomic, strong) dispatch_queue_t queue;
@end
@implementation DispatchBarrierAsyncDemo
- (instancetype)init
{
self = [super init];
if (self) {
self.queue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
}
return self;
}
- (void)otherTest {
for (int i = 0; i < 10; i++) {
[[[NSThread alloc] initWithTarget:self selector:@selector(__read) object:nil] start];
[[[NSThread alloc] initWithTarget:self selector:@selector(__read) object:nil] start];
[[[NSThread alloc] initWithTarget:self selector:@selector(__write) object:nil] start];
}
}
- (void)__read {
dispatch_async(self.queue, ^{
NSLog(@"%s", __func__);
});
}
- (void)__write {
dispatch_barrier_async(self.queue, ^{
sleep(1.0);
NSLog(@"%s", __func__);
});
}
@end