版本记录
版本号 | 时间 |
---|---|
V1.0 | 2017.05.21 |
前言
ios中有好几种锁,比如自旋锁,互斥锁,信号量等等,锁其实是多线程数据安全的一种解决方案,作用就是保证同一时间只有一个线程访问和改变某些敏感数据,这些锁的性能也是差别很大,最近看了几个技术大牛的技术博客,我才发现我以前对锁的理解太肤浅了,心虚的赶紧找资料又开始了深入学习,然后整理出来。前面介绍了几种锁:
1. ios开发中的几种锁(一)
这篇接着讲其他的几种锁。
详情
一、pthread_mutex 互斥锁
ibireme在《不再安全的OSSpinLock》这篇文章中提到性能最好的OSSpinLock不再是线程安全的并把自己开源项目中的OSSpinLock都替换成了pthread_mutex。下面还是先看代码。
1. JJPtheadVC.h
#import <UIKit/UIKit.h>
@interface JJPtheadVC : UIViewController
@end
2. JJPtheadVC.m
#import "JJPtheadVC.h"
#import <pthread.h>
@interface JJPtheadVC ()
@end
@implementation JJPtheadVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
//互斥所
[self aboutPthreadMutex];
}
#pragma mark - Object Private Function
- (void)aboutPthreadMutex
{
static pthread_mutex_t mutexLock;
pthread_mutex_init(&mutexLock, NULL);
NSInteger __block num = 10;
//线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"线程1准备上锁,%@",[NSThread currentThread]);
pthread_mutex_lock(&mutexLock);
num = num + 1;
NSLog(@"线程1--num1=%ld",num);
pthread_mutex_unlock(&mutexLock);
});
//线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"线程2准备上锁,%@",[NSThread currentThread]);
pthread_mutex_lock(&mutexLock);
num = num + 1;
NSLog(@"线程2--num2=%ld",num);
pthread_mutex_unlock(&mutexLock);
});
}
@end
查看结果
2017-05-20 13:27:14.675 lock[3995:185687] 线程2准备上锁,<NSThread: 0x60800007e0c0>{number = 4, name = (null)}
2017-05-20 13:27:14.675 lock[3995:185685] 线程1准备上锁,<NSThread: 0x600000265080>{number = 3, name = (null)}
2017-05-20 13:27:14.675 lock[3995:185687] 线程2--num2=11
2017-05-20 13:27:14.678 lock[3995:185685] 线程1--num1=12
注意:pthread_mutex 中也有个pthread_mutex_trylock(&pLock),和上面提到的 OSSpinLockTry(&oslock)区别在于,前者可以加锁时返回的是 0,否则返回一个错误提示码;后者返回的 YES和NO。
二、pthread_mutex(recursive) 递归锁
根据上面讲述的几个锁,可以发现:加锁后只能有一个线程访问该对象,后面的线程需要排队,并且lock与unlock都是对应出现的,同一线程多次lock是不允许的,而递归锁允许同一个线程在未释放其拥有的锁时反复对该锁进行加锁操作。
下面直接看代码
1. JJPthreadRecursiveVC.h
#import <UIKit/UIKit.h>
@interface JJPthreadRecursiveVC : UIViewController
@end
2. JJPthreadRecursiveVC.m
#import "JJPthreadRecursiveVC.h"
#import <pthread.h>
@interface JJPthreadRecursiveVC ()
@end
@implementation JJPthreadRecursiveVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
//递归锁
[self aboutPthreadMutexRecursive];
}
#pragma mark - Object Private Function
- (void)aboutPthreadMutexRecursive
{
static pthread_mutex_t pLock;
pthread_mutexattr_t attr;
//初始化attr并且给它赋予默认
pthread_mutexattr_init(&attr);
//设置锁类型,这边是设置为递归锁
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&pLock, &attr);
//销毁一个属性对象,在重新进行初始化之前该结构不能重新使用
pthread_mutexattr_destroy(&attr);
//1.线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
static void (^RecursiveBlock)(int);
RecursiveBlock = ^(int value) {
pthread_mutex_lock(&pLock);
if (value > 0) {
NSLog(@"value = %d", value);
NSLog(@"线程 = ,%@",[NSThread currentThread]);
RecursiveBlock(value - 1);
}
pthread_mutex_unlock(&pLock);
};
RecursiveBlock(5);
});
}
@end
直接看输出结果
2017-05-21 17:29:14.341 lock[1271:55126] value = 5
2017-05-21 17:29:14.342 lock[1271:55126] 线程 = ,<NSThread: 0x60800006e440>{number = 3, name = (null)}
2017-05-21 17:29:14.342 lock[1271:55126] value = 4
2017-05-21 17:29:14.343 lock[1271:55126] 线程 = ,<NSThread: 0x60800006e440>{number = 3, name = (null)}
2017-05-21 17:29:14.343 lock[1271:55126] value = 3
2017-05-21 17:29:14.344 lock[1271:55126] 线程 = ,<NSThread: 0x60800006e440>{number = 3, name = (null)}
2017-05-21 17:29:14.344 lock[1271:55126] value = 2
2017-05-21 17:29:14.345 lock[1271:55126] 线程 = ,<NSThread: 0x60800006e440>{number = 3, name = (null)}
2017-05-21 17:29:14.348 lock[1271:55126] value = 1
2017-05-21 17:29:14.349 lock[1271:55126] 线程 = ,<NSThread: 0x60800006e440>{number = 3, name = (null)}
注意:上面的代码如果我们用 pthread_mutex_init(&pLock, NULL) 初始化会出现死锁的情况,递归锁能很好的避免这种情况的死锁。
相关参考技术博客
1.iOS 开发中的八种锁(Lock)
2.不再安全的 OSSpinLock
3. NSRecursiveLock递归锁的使用
4.关于dispatch_semaphore的使用
5.实现锁的多种方式和锁的高级用法
后记
剩下的几种锁,待续哦~~~~