一、定义
解释:
pthread 开头的都是跨平台的,一般是通用的
* 可以在 windows, Linux ,mac 等
* 如果在 iOS 上会用这个锁,那么在其他平台也会使用这把锁。
* 它是互斥锁:mutex
现在有两种锁:
* 互斥锁
* 自旋锁
二、代码演示,静态初始化
// 初始化锁
- (instancetype)init
{
if (self = [super init]) {
/// 初始化锁
/// 但是当 使用属性赋值时,会报错。
/// 是静态初始化,在定义变量的同时,赋值
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
}
return self;
}
@property(nonatomic,assign) pthread_mutex_t mutex;
,赋值 属性 self.mutex = PTHREAD_MUTEX_INITIALIZER;
会报错。PTHREAD_MUTEX_INITIALIZER
查看 #define PTHREAD_MUTEX_INITIALIZER {_PTHREAD_MUTEX_SIG_init, {0}}
self.mutex = {_PTHREAD_MUTEX_SIG_init, {0}};
不可以。会报错。self.mutex = *** ;
其实就是self 调用 setMutex [self setMutex:***];
结构体赋值
正确写法:
struct Date {
int year;
int month;
};
// 2011 给 year,10给month
struct Date date = {2011,10};
不能写成
struct Date date;
date = {2011,10};
这是结构体语法规范
三、初始化
/// 初始化属性
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
/// 初始化锁
pthread_mutex_init(&_mutex, &attr);
/*
* Mutex type attributes
*/
#define PTHREAD_MUTEX_NORMAL 0
#define PTHREAD_MUTEX_ERRORCHECK 1
#define PTHREAD_MUTEX_RECURSIVE 2
#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
PTHREAD_MUTEX_NORMAL
和 PTHREAD_MUTEX_DEFAULT
都是普通锁
PTHREAD_MUTEX_ERRORCHECK
用来检查错误的
PTHREAD_MUTEX_RECURSIVE
递归锁
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
销毁属性
/// 销毁属性
pthread_mutexattr_destroy(&attr);
以上代码,代表初始化完一把 锁
全部代码为:
- (instancetype)init
{
if (self = [super init]) {
/// 初始化属性
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT)
/// 初始化锁
pthread_mutex_init(&_mutex, &attr);
/// 销毁属性
pthread_mutexattr_destroy(&attr);
}
return self;
}
四、细节
细节一:init 时传NULL
PTHREAD_MUTEX_DEFAULT
/// 初始化锁
pthread_mutex_init(&_mutex, NULL);
细节二:不用的时候,要销毁
- (void)dealloc {
pthread_mutex_destroy(&_moneyMutex);
pthread_mutex_destroy(&_ticketMutex);
}
五、例子2
一个方法里面调用另一个方法。两个方法都加锁
代码:
- (void)otherTest {
pthread_mutex_lock(&_mutex);
NSLog(@"%s", __func__);
[self otherTest2];
pthread_mutex_unlock(&_mutex);
}
- (void)otherTest2 {
pthread_mutex_lock(&_mutex);
NSLog(@"%s", __func__);
pthread_mutex_unlock(&_mutex);
}
执行结果: 死锁
解决办法:换锁,两个方法不用一把锁。
没有锁的时候,打印是正常的:
- (void)otherTest {
NSLog(@"%s", __func__);
[self otherTest2];
}
- (void)otherTest2 {
NSLog(@"%s", __func__);
}
如果是递归,也会出现死锁的情况
- (void)otherTest {
pthread_mutex_lock(&_mutex);
NSLog(@"%s", __func__);
// 自己调用自己
[self otherTest];
pthread_mutex_unlock(&_mutex);
}
解决办法: 使用递归锁
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
如果是线程1 、线程2这样,就不是同一个线程。
它会自动判断是否是同一个线程过来加锁。
六、条件
往数组中添加、删除 元素。应该怎么做?
添加元素和删除元素的时候,加同一把锁。
在 otherTest 方法中,调用这两个方法。先条用删除元素,再调用添加元素。
假如:删除元素和添加元素 是在不同线程做的。
想要做的效果是:数组中有元素的时候在删除,没有元素就不删除。
解释:
pthread_cond_wait(&_cond,&_mutex);
这句代码在睡觉的时候,会把锁放开。pthread_cond_signal(&_cond);
这句代码会唤醒pthread_cond_wait(&_cond,&_mutex);
这句代码。pthread_cond_wait(&_cond,&_mutex);
代码会给 _mutex 加锁。然后代码执行到remove 方法中的 [self.data removeLastObject];
,然后就会解除 remove 方法中的 锁。pthread_cond_wait(&_cond,&_mutex);
这个代码,在等待的时候,会 解锁。然后睡觉。当唤醒的时候。会再次加锁。