美文网首页
怎么让线程同步

怎么让线程同步

作者: chdo002 | 来源:发表于2018-05-05 21:41 被阅读9次

    Dispatch Group

    需要在大量任务都执行完成后,执行其他任务,可以用 Dispatch Group

    // 可以理解为一个任务组,组内的任务完成后就会调用dispatch_group_notify
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    dispatch_group_async(group, queue, ^{
        for (int i = 0; i < 1000; i++) {
        if (i == 999) {
            NSLog(@"11111111");
        }
    }
    
    });
    
    dispatch_group_async(group, queue, ^{
        NSLog(@"22222222");
    });
    
    dispatch_group_async(group, queue, ^{
        NSLog(@"33333333");
    });
    
    dispatch_group_notify(group, queue, ^{
        NSLog(@"done");
    });
    
    

    对于网络请求这种异步任务,还需要使用 dispatch_group_enter和dispatch_group_leave,来手动处理下,先上代码

    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        NSLog(@"任务1开始");
        sleep(2);
        NSLog(@"任务1结束");
        dispatch_group_leave(group);
    });
    
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        NSLog(@"任务2开始");
        sleep(1);
        NSLog(@"任务2结束");
        dispatch_group_leave(group);
    });
    
    dispatch_group_notify(group, queue, ^{
        NSLog(@"完成了");
    });
    

    输出为

    17:31:39.314251+0800 testP[29849:2247791] 任务2开始
    17:31:39.314251+0800 testP[29849:2247785] 任务1开始
    17:31:40.317949+0800 testP[29849:2247791] 任务2结束
    17:31:41.318231+0800 testP[29849:2247785] 任务1结束
    17:31:41.318588+0800 testP[29849:2247785] 完成了
    
    

    可以看到任务1和任务2同时执行,因为任务1耗时2秒,所以在任务2后1秒完成,然后发出通知,

    dispatch_group_enter和dispatch_group_leave总是成对出现,不然可能导致group没有被释放,从而没有notify;或者group提前释放,导致EXC_BAD_INSTRUCTION,group提前释放

    dispatch_group_enter和dispatch_group_leave可以理解为给group添加手动计数,dispatch_group_enter会给group加1,dispatch_group_leave就是减一,group初始计数为0。

    当group初始计数为0时,就会执行notify通知,比如如下代码

    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    dispatch_group_notify(group, queue, ^{
        NSLog(@"完成了");
    });
    
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        NSLog(@"任务1开始");
        sleep(2);
        NSLog(@"任务1结束");
        dispatch_group_leave(group);
    });
    
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        NSLog(@"任务2开始");
        sleep(1);
        NSLog(@"任务2结束");
        dispatch_group_leave(group);
    });
    
    
    

    输出为

    17:45:46.296758+0800 testP[30209:2259157] 任务2开始
    17:45:46.296758+0800 testP[30209:2259158] 任务1开始
    17:45:46.296766+0800 testP[30209:2259150] 完成了
    17:45:47.301499+0800 testP[30209:2259157] 任务2结束
    17:45:48.299812+0800 testP[30209:2259158] 任务1结束
    

    将dispatch_group_notify移到最前,就不会在group完成后得到notify,而是提前执行了

    dispatch_barrier_sync 和 dispatch_barrier_async

    20150726170216381.png
    
    dispatch_async(queue, ^{
        NSLog(@"1");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"2");
    });
    dispatch_async(queue, ^{
        NSLog(@"3");
    });
    
    
    // dispatch_barrier_sync 这个和  dispatch_async与dispatch_sync之间的区别类似
    dispatch_barrier_async(queue, ^{
        NSLog(@"000000");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"4");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"5");
    });
    dispatch_async(queue, ^{
        NSLog(@"6");
    });
    

    dispatch_semaphore

    1、dispatch_semaphore_create 创建一个semaphore  就是创建一个全局的变量,小于0时会阻塞当前线程
    2、dispatch_semaphore_signal 发送一个信号       给信号量加1
    3、dispatch_semaphore_wait 等待信号   给信号量减1
    

    这个东西本质是就是立flag,让flag小于0,线程就阻塞了,只有让flag大于0,才能继续

    网上的说明例子

    // 创建队列组
    dispatch_group_t group = dispatch_group_create();
    // 创建信号量,并且设置值为10
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    for (int i = 0; i < 100; i++){
    /*
     *  由于是异步执行的,所以每次循环Block里面的dispatch_semaphore_signal根本还没有执行就会执行dispatch_semaphore_wait,
     *  从而semaphore-1.当循环10此后,semaphore等于0,则会阻塞线程,直到执行了Block的dispatch_semaphore_signal 才会继续执行
     */
    
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        dispatch_group_async(group, queue, ^{
            NSLog(@"%i",i);
            sleep(2);
            // 每次发送信号则semaphore会+1,
            dispatch_semaphore_signal(semaphore);
        });
    }
    
    

    应用1 网络请求

    _block BOOL isok = NO;
    
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);
    Engine *engine = [[Engine alloc] init];
    [engine queryCompletion:^(BOOL isOpen) {
        isok = isOpen;
        dispatch_semaphore_signal(sema);
    } onError:^(int errorCode, NSString *errorMessage) {
        isok = NO;
        dispatch_semaphore_signal(sema);
    }];
    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    // todo what you want to do after net callback
    

    应用2 获取权限

    //创建通讯簿的引用
    addBook=ABAddressBookCreateWithOptions(NULL, NULL);
    //创建一个出事信号量为0的信号
    dispatch_semaphore_t sema=dispatch_semaphore_create(0);
    //申请访问权限
    ABAddressBookRequestAccessWithCompletion(addBook, ^(bool greanted, CFErrorRef error)
    {
        //greanted为YES是表示用户允许,否则为不允许
        if (!greanted) {
            tip=1;
        }
        //发送一次信号
        dispatch_semaphore_signal(sema);
    
    });
    //等待信号触发
    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    
    

    相关文章

      网友评论

          本文标题:怎么让线程同步

          本文链接:https://www.haomeiwen.com/subject/wbnerftx.html