1. OSSpinLock :自旋锁,锁住时处于忙等状态(时刻检查是否解锁)
所在头文件:#import <libkern/OSAtomic.h>
_lock = OS_SPINLOCK_INIT;//初始化。这里初始化一次,不能放在加锁解锁的函数里
//即使不在同一个方法,只要是锁是同一把,就能锁住锁里的代码,只有一块代码在执行
OSSpinLockLock(&_lock);//加锁
//OSSpinLockLockTry 尝试加锁,若是没有锁住,就加个锁。
//要锁的代码
OSSpinLockUnlock(&_lock);//解锁
自旋锁原理,隔一会儿就去检查下锁有没有被放开。
目前锁不安了,出现优先级反转的情况。在开启多个线程的情况下,因为时间片轮转调度算法,有些线程优先级比较高,有些比较低,低优先级的线程加了锁,然而有些线程优先级比较高,系统会优先分配给高优先级的线程,高优先级的线程一直被执行,但是代码被优先级的线程锁着,导致死锁。
2. os_unfair_lock :锁住时线程处于休眠状态,互斥锁
使用需要导入头文件import<os/lock.h>
os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;初始化
os_fair_lock_trylock(&lock);//尝试加锁
os_unfair_look_lock(&lock);//加锁
os_unfair_lock_unlock(&lock);//解锁
3. pthread_mutex
互斥锁,等待的线程会处于休眠状态
- (void)__initMutex:(pthread_mutex_t*)mutex{
//静态初始化。声明时直接初始化
//pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//初始化属性
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
//动态初始化,先声明,运行时再赋值。
pthread_mutex_init(mutex, &attr);
//销毁锁
pthread_mutexattr_destroy(&attr);
}
pthread_mutex_lock(&_mutex);//加锁
pthread_mutex_unlock(&_mutex);//解锁
递归锁:在同一个线程可以重复加锁,加多少次,解多少次。
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);//递归锁,解决循环加锁的问题
pthread_cond_t条件
pthread_cond_t cond;//声明
pthread_cond_init(&_cond, NULL);//初始化
假设:
- __remove函数在线程1,__add在线程2,两个线程同时执行,但是线程1的__remove函数先加上了锁,此后__add函数就得等线程1的锁放开才能执行。
- 线程1的remove函数执行,发现data里元素个数小于0, 调用pthread_cond_wait(&condition, &_mutex)这句代码,让当前线程处于睡觉的状态,并且放开锁。
- 此时线程2的锁检测到线程1的锁被放开了,就在线程2加上锁,给data添加数据,然后pthread_cond_signal(&condition)唤醒因condition条件没达到就睡眠的线程,然后解开锁。
- 随着锁解开,之前进入睡眠的线程1就给锁锁住,然移除数组里的元素,最后解开锁。
注:pthread_cond_wait(&condition,&mutex)是唤醒所有因condition而等待的线程。
- (void)__remove
{
pthread_mutex_lock(&_mutex);
if (self.data.count == 0) {
pthread_cond_wait(&_cond, &_mutex);
}
[self.data removeLastObject];
pthread_mutex_unlock(&_mutex);
}
线程2代码
- (void)__add
{
pthread_mutex_lock(&_mutex);
[self.data addObject:@"Test"];
pthread_cond_signal(&_cond);//唤醒上面在等待的s线程
pthread_mutex_unlock(&_mutex);
}
4. NSLock、NSRecursiveLock
NSLock是对mutex的封装,接口
@interface NSLock:NSObject<NSLocking>
-(BOOL)tryLock;//尝试加锁
-(BOOL)lockBeforeDate:(NSDate*)limt//在一定时间内,如果锁还是在锁着,在时间内等着,要是在时间内锁开了,就加个锁,返回YES,过了时间就不等,返回NO
......
@end
@protocol NSLocking
- (void)lock;
- (void)unlock;
@end
5. NSCondition
是对mutex和cond的封装
@interface NSCondition:NSObject <NSLocking>
- (void)wait;
- (BOOL)waitUntilDate:(NSDate*)limit;
- (void)signal;//唤醒
- (void)broadcast;//唤醒所有等待线程
6. NSConditionLock
是对NSCondition的进一步封装,通过一个数字对锁做标记,只有数字相同才能加锁
@interface NSConditionLock:NSObject<NSLocking>
//初始化,传入锁的条件或者说起始标记
-(instancetype)initWithCondition:(NSInterger)condition;
//当锁的条件或标记是condition
-(void)lockWhenCondition::(NSInterger)condition;
-(BOOL)tyLock;
-(BOOL)tyLockWhenCondition:(NSInteger)condition;
//解锁,并修改锁的条件为condition
-(BOOL)unlockWhenCondition::(NSInterger)condition;
//一定时间内加锁
-(BOOL)lockBeforeDate:(NSDate*)limit;
//一定时间内达到条件加锁
-(BOOL)lockWhenCondition:(NSInteger)contion:(NSinteger)condition beforeDate:(NSDate*)limit;
7. 使用串行队列实现锁
self.moneyQueue=dispatch_queue_create("moneyQueue", DISPATCH_QUEUE_SERIAL);
- (void)saveMoney
{
dispatch_async(self.moneyQueue, ^{
[super saveMoney];
});
}
- (void)drawMoney
{
dispatch_async(self.moneyQueue, ^{
[super drawMoney];
});
}
把存钱取钱加在同一个队列里,保证存取同时只能进行一个。
8. dispatch_semaphore_t
使用信号量来实现锁,信号量初始化为1,保证同时只能进行一个。
self.semaphore = dispatch_semaphore_create(5);//初始化
- (void)otherTest
{
for (int i=0; i<20; i++) {
[[[NSThread alloc]initWithTarget:self selector:@selector(test) object:nil]start];
}
}
- (void)test{
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
sleep(1);
NSLog(@"test- %@",[NSThread currentThread]);
dispatch_semaphore_signal(self.semaphore);
}
9. @synchronized
可以把任意对象当锁,使用最方便,但是性能最低,底层封装的最复杂,同时也支持递归加锁。
- (void)drawMoney
{
@synchronized (self) {
[super drawMoney];
}
}
- (void)saveMoney
{
@synchronized (self) {
[super saveMoney];
}
}
- (void)otherTest{
//只是为了说明可以递归加锁,这里会无限循环
@synchronized ([self class]) {
NSLog(@"123");
[self otherTest];
}
}
网友评论