怎么让线程同步

2018-05-05  本文已影响9人  chdo002

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);

上一篇下一篇

猜你喜欢

热点阅读