iOS - 多线程中 condition wait

使用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 

        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_broad       cast,把该线程唤醒,使pthread_cond_wait()通过(返回)时,该线程又自动获得该mutex。
  pthread_cond_signal函数的作用是发送一个信号给另外一个正在处于阻塞等待状态的线程,使其脱离阻塞状态,继续执行.如果没有线程处在阻塞等待状态,pthread_cond_signal也会成功返回。
  使用pthread_cond_signal一般不会有“惊群现象”产生,他最多只给一个线程发信号。假如有多个线程正在阻塞等待着这个条件变量的话,那么是根据各等待线程优先级的高低确定哪个线程接收到信号开始继续执行。如果各线程优先级相同,则根据等待时间的长短来确定哪个线程获得信号。但无论如何一个pthread_cond_signal调用最多发信一次。
  但是pthread_cond_signal在多处理器上可能同时唤醒多个线程,当你只能让一个线程处理某个任务时,其它被唤醒的线程就需要继续 wait,而且规范要求pthread_cond_signal至少唤醒一个pthread_cond_wait上的线程,其实有些实现为了简单在单处理器上也会唤醒多个线程. 
   另外,某些应用,如线程池,pthread_cond_broadcast唤醒全部线程,但我们通常只需要一部分线程去做执行任务,所以其它的线程需要继续wait.所以强烈推荐对pthread_cond_wait() 使用while循环来做条件判断.

/**

 *接下来展示一下小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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值