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

怎么让线程同步

作者: 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);

相关文章

  • 怎么让线程同步

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

  • OpenMP多线程——Parallel for

    多线程——线程同步 数据竞争问题 线程互斥同步——critical 线程互斥同步——atmoic 线程互斥同步——...

  • iOS_2016最新版面试题(附答案)

    每天四道题,让精彩填满生活... 1、多线程同步和异步的区别。iOS如何实现多线程的同步? 答:同步就是指一个线程...

  • iOS线程同步

    iOS线程同步 iOS线程同步

  • juc并发组件(二)Semaphore 信号量源码解析

    semaphore 主要用来对多个资源,在多线程环境下,让线程对多个资源保持同步访问。线程之间同步主要依靠许可证。...

  • GCD 让线程同步

    1.dispatch_group 调度组2.dispatch_barrier 栅栏块3.dispatch_sema...

  • 线程的基本语法

    线程同步[解决线程安全问题] 解决线程安全问题 线程同步方式一:同步代码 语法基本 synchronized (同...

  • iOS多线程小结

    同步异步串行并行 同步串行:不开启线程 同步并行:不开启线程 异步串行:最多开启一个线程 异步并行:开启线程 同步...

  • java并发编程实战读书笔记:第三章 对象的共享

    上一章讲的是怎么通过同步来避免让多个线程同时访问相同的数据。而这一章要讲的是如何让多个线程同时安全的访问一个对象。...

  • 线程池

    Java多线程 线程的同步是Java多线程编程的重点和难点,往往让人搞不清楚什么是竞争资源、什么时候需要考虑同步,...

网友评论

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

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