NSCondition
**介绍:**条件锁,是对条件变量和互斥量的封装,互斥量用于保护条件变量的修改,而条件变量实现线程之间的同步。条件既充当当前线程中的锁又充当检查条件,条件锁在执行条件触发的任务时保护临界资源不被其他线程修改,检查条件要求条件在线程继续执行其任务之前为真,条件不成立时,阻塞线程。直到另一个线程向条件对象发出信号为止它都一直保持阻塞状态。
@interface NSCondition : NSObject <NSLocking> {
@private
void *_priv;
}
- (void)wait;//直到信号量可用,否则让线程进入等待状态
- (BOOL)waitUntilDate:(NSDate *)limit;//阻塞当前线程,直到收到唤醒信号或超时,若高线程被信号唤醒,返回YES,否则返回NO
- (void)signal;//唤醒等待的线程,若要唤醒多个线程,需要调用多次
- (void)broadcast;//唤醒所有等待的线程
@property (nullable, copy) NSString *name;
实现:
1、条件变量的初始化
- (id) init
{
if (nil != (self = [super init]))
{
if (0 != pthread_cond_init(&_condition, NULL))
{
DESTROY(self);
}
else if (0 != pthread_mutex_init(&_mutex, &attr_reporting))
{
pthread_cond_destroy(&_condition);
DESTROY(self);
}
}
return self;
}
首先,我们分析一下-init方法,该方法先使用pthread_cond_init初始化一个条件变量,初始化成功之后再使用pthread_mutex_init初始化一个锁,如果任何一步初始化失败,都释放资源。
从上面我们可以看出NSCondition的是对条件变量和互斥锁的封装,下面我们看一下条件变量的相关知识。
(1)条件变量的初始化
pthread_cond_init(pthread_cont_t *cv, const pthread_condattr_t *cattr);
cv是指向结构pthread_cond_t的指针,cond_attr是一个指向结构pthread_condattr_t的指针。结构 pthread_condattr_t是条件变量的属性结构,我们可以用它来设置条件变量是进程内可用还是进程间可用,默认值是 PTHREAD_ PROCESS_PRIVATE,即此条件变量被同一进程内的各个线程使用,该函数初始化成功返回零,也可以使用静态变量初始化,如下
pthread_cond_t condition = PTHREAD_COND_INITIALIZER;//设置cattr为null的pthread_cond_init()等效
(2)条件变量的销毁
pthread_cond_destroy(pthread_cont_t *cv);
销毁条件变量,但是没有释放存储条件变量的空间
2、阻塞条件变量
(1) - (void) wait
- (void) wait
{
pthread_cond_wait(&_condition, &_mutex);
}
其中pthread_cond_wait()阻塞当前线程,等待pthread_cond_signal()或pthread_cond_broadcast来唤醒。 pthread_cond_wait() 必须与pthread_mutex 配套使用。pthread_cond_wait() 函数一进入wait状态就会自动release mutex。当其他线程通过 pthread_cond_signal() 或pthread_cond_broadcast ,把该线程唤醒,使 pthread_cond_wait()通过(返回)时,该线程又自动获得该mutex 。
(2) - (BOOL) waitUntilDate: (NSDate*)limit
- (BOOL) waitUntilDate: (NSDate*)limit
{
NSTimeInterval ti = [limit timeIntervalSince1970];
double secs, subsecs;
struct timespec timeout;
int retVal = 0;
// Split the float into seconds and fractions of a second
subsecs = modf(ti, &secs);
timeout.tv_sec = secs;
// Convert fractions of a second to nanoseconds
timeout.tv_nsec = subsecs * 1e9;
/* NB. On timeout the lock is still held even through condition is not met
*/
retVal = pthread_cond_timedwait(&_condition, &_mutex, &timeout);
if (retVal == 0)
{
return YES;
}
if (retVal == ETIMEDOUT)
{
return NO;
}
if (retVal == EINVAL)
{
NSLog(@"Invalid arguments to pthread_cond_timedwait");
}
return NO;
}
3、解锁
- (void) signal
{
pthread_cond_signal(&_condition);
}
pthread_cond_signal 函数的作用是发送一个信号给另外一个正在处于阻塞等待状态的线程,使其脱离阻塞状态,继续执行.如果没有线程处在阻塞等待状态,pthread_cond_signal也会成功返回。使用pthread_cond_signal一般不会有“惊群现象”产生,他最多只给一个线程发信号。假如有多个线程正在阻塞等待着这个条件变量的话,那么是根据各等待线程优先级的高低确定哪个线程接收到信号开始继续执行。如果各线程优先级相同,则根据等待时间的长短来确定哪个线程获得信号。但无论如何一个pthread_cond_signal调用最多发信一次。
@interface NSCondition : NSObject <NSLocking>
{
gs_cond_t _condition;
gs_mutex_t _mutex;
NSString *_name;
}
参考:https://www.yuque.com/365cshitou/ontheroad/nscondition?language=en-us