使用NSCondition,实现多线程同步。。。举个列子 消费者跟生产者。。。
现在传言8s要出了。。
- 消费者想买8s。现在还没有8s。消费者等待8s生产。
- 生产了一个产品,唤起消费者去买8s。解锁.。。
一般在多线程编程中都会用到condition_wait,“条件变量与互斥量一起使用从可以允许线程以无竞争的方式等待特定的条件发生。为什么必须一起使用呢?1)假如当某个资源满足了一定的条件时它要发送信号告诉需要它的线程,假如现在资源为空,条件不满足,那么线程就要等待,那么在线程条件检查时刻t1,到线程放到表上的时刻t2,在t1到t2这段时间内,可能资源来了,然而CPU调度到另外的工作进程上了,这样条件就不能改变,这样线程就错过了条件变化,虽然等线程放到队列上后,资源变化可以通知线程,但是会有时间延迟。2)传递给pthread_cond_wait(pthread_cont_t *restrict cond, pthread_mutex_t *restrict mutex)中的mutex必须是已经锁住的,如果这个互斥锁不是锁住的,那么假如满足条件,线程一对资源访问的同时线程二也可能访问,就造成了资源的不一致。所以这个过程还是挺复杂的,当需要等待时,把一个资源的互斥量和等待条件一同传给这个wait函数,这个wait函数把线程放到这个条件的等待队列上,然后对互斥量解锁(注意这两步是个原子操作,具体原因如1)。解锁一来可以让条件发生(如果死守着资源,那么资源也就不会变了),二来可以让其他线程同时访问资源,同样可以检查条件。”
以前只理解了在放入等待队列前的一些操作,pthread_cond_wait这个方法在做线程池调用的时候非常常见,用这个接口可以减少多线程的时候的锁竞争,在没有资源的时候进入sleep状态,这个时候是不耗费cpu的,当有资源的时候发送一个或者唤醒所有的线程,否则在线程中只能定时去检查资源是否存在,这样会定时的产生锁竞争,最重要的是浪费了cpu不必要的调度。发送一个signal可以有资源的时候不至于使得很多线程去竞争这个资源,一般而言一个signal只会唤醒一个队列中的线程,至于唤醒的策略“根据各等待线程优先级的高低确定哪个线程接收到信号开始继续执行。如果各线程优先级相同,则根据等待时间的长短来确定哪个线程获得信号”
参考:
http://blog.csdn.net/hudashi/article/details/7709421,http://apps.hi.baidu.com/share/detail/19786281,http://hi.baidu.com/boobleoo0/blog/item/5f935039a37c58f8b311c77f.html
/**
*接下来展示一下小demo:
*/
// ViewController.m
// ZJJWaitSBDemo
//
// Created by ZJJ on 2017/8/10.
// Copyright © 2017年 ZJJ. All rights reserved.
//
#import "ViewController.h"
@interface ViewController () {
NSCondition *_condition;
int _index;
NSTimer *_timer;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_condition = [[NSCondition alloc] init];
[self openLines];
}
#pragma mark - 开辟两个线程方法
- (void)openLines {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[_condition lock];
if (_index < 10) {
NSLog(@"小于10,还需等待!");
[_condition wait];
}
NSLog(@"终于大于10了,index=%d",_index);
[_condition unlock];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[_condition lock];
/**
*这里用while循环也可以,之所以用下面的定时器,只是想看下慢动作回放
while (_index<10) {
_index++;
}
[_condition signal];
*/
if (_index == 0) {
NSLog(@"开启定时器,让其逐次增长!!!");
[self openTimer];
}
[_condition unlock];
});
}
- (void)openTimer {
if (_timer == nil) {
dispatch_async(dispatch_get_main_queue(), ^{
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(doSomeThing) userInfo:nil repeats:YES];
NSLog(@"已开启");
});
}
}
- (void)closeTimer {
[_timer invalidate];
_timer = nil;
}
- (void)doSomeThing {
_index ++;
NSLog(@"逐渐增加的index=%d",_index);
if (_index>=10) {
[_condition signal];
[self closeTimer];
}
}
后台输出结果:
2017-08-10 16:57:54.501 ZJJWaitSBDemo[2645:233398] 开启定时器,让其逐次增长!!!
2017-08-10 16:57:54.501 ZJJWaitSBDemo[2645:233416] 小于10,还需等待!
2017-08-10 16:57:54.506 ZJJWaitSBDemo[2645:233364] 已开启
2017-08-10 16:57:55.506 ZJJWaitSBDemo[2645:233364] 逐渐增加的index=1
2017-08-10 16:57:56.507 ZJJWaitSBDemo[2645:233364] 逐渐增加的index=2
2017-08-10 16:57:57.506 ZJJWaitSBDemo[2645:233364] 逐渐增加的index=3
2017-08-10 16:57:58.507 ZJJWaitSBDemo[2645:233364] 逐渐增加的index=4
2017-08-10 16:57:59.507 ZJJWaitSBDemo[2645:233364] 逐渐增加的index=5
2017-08-10 16:58:00.507 ZJJWaitSBDemo[2645:233364] 逐渐增加的index=6
2017-08-10 16:58:01.507 ZJJWaitSBDemo[2645:233364] 逐渐增加的index=7
2017-08-10 16:58:02.507 ZJJWaitSBDemo[2645:233364] 逐渐增加的index=8
2017-08-10 16:58:03.508 ZJJWaitSBDemo[2645:233364] 逐渐增加的index=9
2017-08-10 16:58:04.506 ZJJWaitSBDemo[2645:233364] 逐渐增加的index=10
2017-08-10 16:58:04.507 ZJJWaitSBDemo[2645:233416] 终于大于10了,index=10