当前位置: 移动技术网 > 移动技术>移动开发>IOS > iOS-GCD的理解与使用

iOS-GCD的理解与使用

2020年08月14日  | 移动技术网移动技术  | 我要评论

一、任务和队列

任务:在线程中执行的操作;执行任务有两种方式:同步执行异步执行

  • 同步执行:同步添加任务到队列中,前一个任务没有执行完,后面不能执行。不开辟新线程
  • 异步执行:异步添加任务到队列中,任务同一时间可以一起执行。开启多个新线程

队列:队列是一种特殊的线性表,采用 FIFO(先进先出)的原则;GCD中有两种队列:串行队列并发队列

  • 串行队列:每次只有一个任务被执行,让任务一个接着一个地执行
  • 并发队列:可以让多个任务并发(同时)执行

二、队列和任务的创建

1、队列

  • 使用dispatch_queue_create来创建队列对象
// 串行队列
dispatch_queue_t queue = dispatch_queue_create("com.test", DISPATCH_QUEUE_SERIAL);
// 并发队列
dispatch_queue_t queue1 = dispatch_queue_create("com.test", DISPATCH_QUEUE_CONCURRENT);

特殊队列:
主队列dispatch_get_main_queue() 实质上就是一个普通的串行队列,负责在主线程上调度任务,通常是返回主线程更新UI的时候使用

// 主队列
dispatch_queue_t queue = dispatch_get_main_queue();

全局并发队列dispatch_get_global_queue 全局并发队列是就是一个并发队列,是为了让我们更方便的使用多线程

// 全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

2、任务

  • 同步执行任务创建:dispatch_sync
  • 异步执行任务创建:dispatch_async
// 同步执行任务创建
dispatch_sync(queue, ^{
    // 执行任务代码
});
// 异步执行任务创建
dispatch_async(queue, ^{
    // 执行任务代码
});

三、GCD的使用

GCD 有两种队列(串行队列 / 并发队列),两种任务执行方式(同步执行 / 异步执行),那么就有了四种不同的组合方式:同步执行 + 串行队列、同步执行 + 并发队列、异步执行 + 串行队列、异步执行 + 并发队列
除了以上四种组合,我们还有两种特殊队列,全局并发队列可以作为普通并发队列来使用可忽略;主队列是特殊的串行队列,需要注意一下;这样就多处两种不同的组合:同步执行 + 主队列、 异步执行 + 主队列

下面来看看不同组合方式的区别:

任务 串行队列 并发队列 主队列
同步 没有开启新线程,串行执行任务 没有开启新线程,串行执行任务 死锁
异步 开启1条新线程,串行执行任务 开启新线程,并发执行任务 没有开启新线程,串行执行任务

1、组合方式

  • 串行同步

不会开启新线程,执行完一个任务,再执行下一个任务。

- (void)syncSerial {
    // 串行队列
    dispatch_queue_t queue = dispatch_queue_create("com.test", DISPATCH_QUEUE_SERIAL);

    // 同步执行
    dispatch_sync(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"串行同步1   %@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"串行同步2   %@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"串行同步3   %@",[NSThread currentThread]);
        }
    });
    
}

打印结果
2020-08-13 16:46:07.992056+0800 ModuleProject[16844:390970] 串行同步1   <NSThread: 0x6000011c0080>{number = 1, name = main}
2020-08-13 16:46:07.992250+0800 ModuleProject[16844:390970] 串行同步1   <NSThread: 0x6000011c0080>{number = 1, name = main}
2020-08-13 16:46:07.992372+0800 ModuleProject[16844:390970] 串行同步1   <NSThread: 0x6000011c0080>{number = 1, name = main}
2020-08-13 16:46:07.992509+0800 ModuleProject[16844:390970] 串行同步2   <NSThread: 0x6000011c0080>{number = 1, name = main}
2020-08-13 16:46:07.992804+0800 ModuleProject[16844:390970] 串行同步2   <NSThread: 0x6000011c0080>{number = 1, name = main}
2020-08-13 16:46:07.993153+0800 ModuleProject[16844:390970] 串行同步2   <NSThread: 0x6000011c0080>{number = 1, name = main}
2020-08-13 16:46:07.993301+0800 ModuleProject[16844:390970] 串行同步3   <NSThread: 0x6000011c0080>{number = 1, name = main}
2020-08-13 16:46:07.993401+0800 ModuleProject[16844:390970] 串行同步3   <NSThread: 0x6000011c0080>{number = 1, name = main}
2020-08-13 16:46:07.993536+0800 ModuleProject[16844:390970] 串行同步3   <NSThread: 0x6000011c0080>{number = 1, name = main}
  • 串行异步

开启新线程,任务是串行的,按顺序执行任务

- (void)asyncSerial {
    // 串行队列
    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);

    // 同步执行
    dispatch_async(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"串行异步1   %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"串行异步2   %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"串行异步3   %@",[NSThread currentThread]);
        }
    });
    NSLog(@"结束  %@",[NSThread currentThread]);
}

打印结果
2020-08-13 17:04:14.468515+0800 ModuleProject[17093:404582] 结束  <NSThread: 0x600001c50400>{number = 1, name = main}
2020-08-13 17:04:14.468541+0800 ModuleProject[17093:404761] 串行异步1   <NSThread: 0x600001c1ce40>{number = 4, name = (null)}
2020-08-13 17:04:14.468740+0800 ModuleProject[17093:404761] 串行异步1   <NSThread: 0x600001c1ce40>{number = 4, name = (null)}
2020-08-13 17:04:14.468876+0800 ModuleProject[17093:404761] 串行异步1   <NSThread: 0x600001c1ce40>{number = 4, name = (null)}
2020-08-13 17:04:14.468999+0800 ModuleProject[17093:404761] 串行异步2   <NSThread: 0x600001c1ce40>{number = 4, name = (null)}
2020-08-13 17:04:14.469111+0800 ModuleProject[17093:404761] 串行异步2   <NSThread: 0x600001c1ce40>{number = 4, name = (null)}
2020-08-13 17:04:14.469232+0800 ModuleProject[17093:404761] 串行异步2   <NSThread: 0x600001c1ce40>{number = 4, name = (null)}
2020-08-13 17:04:14.469364+0800 ModuleProject[17093:404761] 串行异步3   <NSThread: 0x600001c1ce40>{number = 4, name = (null)}
2020-08-13 17:04:14.470013+0800 ModuleProject[17093:404761] 串行异步3   <NSThread: 0x600001c1ce40>{number = 4, name = (null)}
2020-08-13 17:04:14.470304+0800 ModuleProject[17093:404761] 串行异步3   <NSThread: 0x600001c1ce40>{number = 4, name = (null)}
  • 并发同步

不会开启新线程,执行完一个任务,再执行下一个任务。

- (void)syncConcurrent {

    // 并发队列
    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    // 同步执行
    dispatch_sync(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"并发同步1   %@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"并发同步2   %@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"并发同步3   %@",[NSThread currentThread]);
        }
    });
    NSLog(@"结束  %@",[NSThread currentThread]);
}

打印结果
2020-08-13 17:22:39.528821+0800 ModuleProject[17314:418018] 并发同步1   <NSThread: 0x6000010608c0>{number = 1, name = main}
2020-08-13 17:22:39.528998+0800 ModuleProject[17314:418018] 并发同步1   <NSThread: 0x6000010608c0>{number = 1, name = main}
2020-08-13 17:22:39.529105+0800 ModuleProject[17314:418018] 并发同步1   <NSThread: 0x6000010608c0>{number = 1, name = main}
2020-08-13 17:22:39.529255+0800 ModuleProject[17314:418018] 并发同步2   <NSThread: 0x6000010608c0>{number = 1, name = main}
2020-08-13 17:22:39.529365+0800 ModuleProject[17314:418018] 并发同步2   <NSThread: 0x6000010608c0>{number = 1, name = main}
2020-08-13 17:22:39.529458+0800 ModuleProject[17314:418018] 并发同步2   <NSThread: 0x6000010608c0>{number = 1, name = main}
2020-08-13 17:22:39.529551+0800 ModuleProject[17314:418018] 并发同步3   <NSThread: 0x6000010608c0>{number = 1, name = main}
2020-08-13 17:22:39.529684+0800 ModuleProject[17314:418018] 并发同步3   <NSThread: 0x6000010608c0>{number = 1, name = main}
2020-08-13 17:22:39.530157+0800 ModuleProject[17314:418018] 并发同步3   <NSThread: 0x6000010608c0>{number = 1, name = main}
2020-08-13 17:22:39.530727+0800 ModuleProject[17314:418018] 结束  <NSThread: 0x6000010608c0>{number = 1, name = main}

  • 并发异步
    开启多线程,任务交替执行
- (void)asyncConcurrent {
        
    // 并发队列
    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    
    // 异步执行
    dispatch_async(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"并发异步1   %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"并发异步2   %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"并发异步3   %@",[NSThread currentThread]);
        }
    });
    NSLog(@"结束  %@",[NSThread currentThread]);
}

打印结果
2020-08-13 17:31:06.193967+0800 ModuleProject[17457:426793] 并发异步2   <NSThread: 0x60000176b800>{number = 4, name = (null)}
2020-08-13 17:31:06.193966+0800 ModuleProject[17457:426621] 结束  <NSThread: 0x60000174cec0>{number = 1, name = main}
2020-08-13 17:31:06.193991+0800 ModuleProject[17457:426795] 并发异步1   <NSThread: 0x60000176b580>{number = 3, name = (null)}
2020-08-13 17:31:06.194006+0800 ModuleProject[17457:426791] 并发异步3   <NSThread: 0x6000017186c0>{number = 6, name = (null)}
2020-08-13 17:31:06.194162+0800 ModuleProject[17457:426793] 并发异步2   <NSThread: 0x60000176b800>{number = 4, name = (null)}
2020-08-13 17:31:06.194162+0800 ModuleProject[17457:426795] 并发异步1   <NSThread: 0x60000176b580>{number = 3, name = (null)}
2020-08-13 17:31:06.194168+0800 ModuleProject[17457:426791] 并发异步3   <NSThread: 0x6000017186c0>{number = 6, name = (null)}
2020-08-13 17:31:06.194280+0800 ModuleProject[17457:426793] 并发异步2   <NSThread: 0x60000176b800>{number = 4, name = (null)}
2020-08-13 17:31:06.194305+0800 ModuleProject[17457:426795] 并发异步1   <NSThread: 0x60000176b580>{number = 3, name = (null)}
2020-08-13 17:31:06.194308+0800 ModuleProject[17457:426791] 并发异步3   <NSThread: 0x6000017186c0>{number = 6, name = (null)}
  • 主队列同步
    会发生死锁,程序崩溃。
    主队列同步,把任务放到了主线程的队列中。同步执行会等待当前队列中的任务执行完毕,才会接着执行。那么当我们把 任务 1 追加到主队列中,任务 1 就在等待主线程处理完 syncMain 任务。而syncMain 任务需要等待 任务 1 执行完毕,才能接着执行。现在的情况就是 syncMain 任务和 任务 1 都在等对方执行完毕产生死锁
- (void)syncMain {
    // 主队列
    dispatch_queue_t queue = dispatch_get_main_queue();
    // 崩溃
    dispatch_sync(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"主队列同步1   %@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"主队列同步2   %@",[NSThread currentThread]);
        }
    });
    NSLog(@"结束  %@",[NSThread currentThread]);
}
  • 主队列异步
    在主线程中任务按顺序执行
- (void)asyncMain {

    // 主队列
    dispatch_queue_t queue = dispatch_get_main_queue();

    dispatch_async(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"主队列异步1   %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"主队列异步2   %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"主队列异步3   %@",[NSThread currentThread]);
        }
    });
    NSLog(@"结束  %@",[NSThread currentThread]);

}

打印结果
2020-08-13 17:53:06.936163+0800 ModuleProject[17714:442887] 结束  <NSThread: 0x6000001c4d80>{number = 1, name = main}
2020-08-13 17:53:07.029229+0800 ModuleProject[17714:442887] 主队列异步1   <NSThread: 0x6000001c4d80>{number = 1, name = main}
2020-08-13 17:53:07.029465+0800 ModuleProject[17714:442887] 主队列异步1   <NSThread: 0x6000001c4d80>{number = 1, name = main}
2020-08-13 17:53:07.029620+0800 ModuleProject[17714:442887] 主队列异步1   <NSThread: 0x6000001c4d80>{number = 1, name = main}
2020-08-13 17:53:07.029767+0800 ModuleProject[17714:442887] 主队列异步2   <NSThread: 0x6000001c4d80>{number = 1, name = main}
2020-08-13 17:53:07.029891+0800 ModuleProject[17714:442887] 主队列异步2   <NSThread: 0x6000001c4d80>{number = 1, name = main}
2020-08-13 17:53:07.030031+0800 ModuleProject[17714:442887] 主队列异步2   <NSThread: 0x6000001c4d80>{number = 1, name = main}
2020-08-13 17:53:07.030137+0800 ModuleProject[17714:442887] 主队列异步3   <NSThread: 0x6000001c4d80>{number = 1, name = main}
2020-08-13 17:53:07.030223+0800 ModuleProject[17714:442887] 主队列异步3   <NSThread: 0x6000001c4d80>{number = 1, name = main}
2020-08-13 17:53:07.030405+0800 ModuleProject[17714:442887] 主队列异步3   <NSThread: 0x6000001c4d80>{number = 1, name = main}

2、GCD 线程间的通信

// 线程间通信
- (void)communication {
    // 全局并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 主队列
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        // 耗时操作放这里
        
        // 回到主线程
        dispatch_async(mainQueue, ^{
            // 追加在主线程中执行的任务
        });
    });
}

3、GCD 栅栏方法

当任务需要异步执行两组操作,第一组完成之后才能进行第二组的操作。这时候就用了到GCD的栅栏方法dispatch_barrier_async

// 栅栏方法 dispatch_barrier_async
- (void)barrierAsync {
    dispatch_queue_t queue = dispatch_queue_create("com.test", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        // 追加任务 1
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
    });
    dispatch_async(queue, ^{
        // 追加任务 2
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    dispatch_barrier_async(queue, ^{
        // 追加任务 barrier
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"barrier---%@",[NSThread currentThread]);// 打印当前线程
    });
    
    dispatch_async(queue, ^{
        // 追加任务 3
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
    });
}

打印结果
2020-08-12 17:01:20.653139+0800 ModuleProject[9201:308471] 2---<NSThread: 0x60000242c480>{number = 3, name = (null)}
2020-08-12 17:01:20.653132+0800 ModuleProject[9201:308467] 1---<NSThread: 0x60000242c4c0>{number = 4, name = (null)}
2020-08-12 17:01:22.656516+0800 ModuleProject[9201:308471] barrier---<NSThread: 0x60000242c480>{number = 3, name = (null)}
2020-08-12 17:01:24.660381+0800 ModuleProject[9201:308471] 3---<NSThread: 0x60000242c480>{number = 3, name = (null)}

4、GCD 队列组

当需要分别异步执行多个耗时任务,然后当多个耗时任务都执行完毕后再回到主线程执行任务。这时候我们可以用到 GCD 的队列组

  • dispatch_group_notify
    通过队列组的 dispatch_group_async 先把任务放到队列中,然后将队列放入队列组中;监听 group 中任务的完成状态,当所有的任务都执行完成后,追加任务到 group 中,并执行任务
// 队列组 dispatch_group_notify
 - (void)groupNotify {
    dispatch_group_t group =  dispatch_group_create();
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 追加任务 1
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 追加任务 2
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // 等前面的异步任务 1、任务 2 都执行完毕后,回到主线程执行下边任务
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
    });
    NSLog(@"4---%@",[NSThread currentThread]);      // 打印当前线程
}
 
打印结果
2020-08-12 20:57:08.991816+0800 ModuleProject[1570:43381] 4---<NSThread: 0x60000015cdc0>{number = 1, name = main}
2020-08-12 20:57:10.995200+0800 ModuleProject[1570:43489] 1---<NSThread: 0x60000017f540>{number = 6, name = (null)}
2020-08-12 20:57:10.995198+0800 ModuleProject[1570:43488] 2---<NSThread: 0x600000113600>{number = 4, name = (null)}
2020-08-12 20:57:12.996592+0800 ModuleProject[1570:43381] 3---<NSThread: 0x60000015cdc0>{number = 1, name = main}
  • dispatch_group_wait
    dispatch_group_notify类似功能但是它阻塞当线程 ,等待指定的 group 中的任务执行完成后,才会往下继续执行。
/**
 * 队列组 dispatch_group_wait
 */
- (void)groupWait {
    dispatch_group_t group =  dispatch_group_create();
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 追加任务 1
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 追加任务 2
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    // 等待上面的任务全部完成后,会往下继续执行(会阻塞当前线程)
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    
    NSLog(@"4---%@",[NSThread currentThread]);      // 打印当前线程

}

打印结果
2020-08-12 21:00:30.398928+0800 ModuleProject[1618:46148] 1---<NSThread: 0x6000022f4e40>{number = 3, name = (null)}
2020-08-12 21:00:30.398934+0800 ModuleProject[1618:46144] 2---<NSThread: 0x6000022f1c00>{number = 6, name = (null)}
2020-08-12 21:00:30.399253+0800 ModuleProject[1618:46065] 4---<NSThread: 0x6000022b8240>{number = 1, name = main}
  • dispatch_group_enter、dispatch_group_leave
    什么时候会用到这个方法?
    在dispatch_group_async()里使用dispatch_async()方法,dispatch_group_notify不是在最后执行的。
- (void)groupEnterAndLeave {
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        for (NSInteger i =0; i<3; i++) {
            sleep(1);
            NSLog(@"任务1-异步任务执行-:%ld,thread:%@",(long)i,[NSThread currentThread]);
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        for (NSInteger i =0; i<3; i++) {
            sleep(1);
            NSLog(@"任务2-异步任务执行-:%ld,thread:%@",(long)i,[NSThread currentThread]);
        }
        dispatch_group_leave(group);
    });
    //等待上面的任务全部完成后,会收到通知执行block中的代码 (不会阻塞线程)
    dispatch_group_notify(group, queue, ^{
        NSLog(@"全部任务执行完成,thread:%@",[NSThread currentThread]);
    });
}

打印结果
2020-08-12 21:13:23.637769+0800 ModuleProject[1815:57379] 任务2-异步任务执行-:0,thread:<NSThread: 0x600002129b00>{number = 3, name = (null)}
2020-08-12 21:13:23.637756+0800 ModuleProject[1815:57377] 任务1-异步任务执行-:0,thread:<NSThread: 0x60000215ecc0>{number = 4, name = (null)}
2020-08-12 21:13:24.639234+0800 ModuleProject[1815:57377] 任务1-异步任务执行-:1,thread:<NSThread: 0x60000215ecc0>{number = 4, name = (null)}
2020-08-12 21:13:24.639234+0800 ModuleProject[1815:57379] 任务2-异步任务执行-:1,thread:<NSThread: 0x600002129b00>{number = 3, name = (null)}
2020-08-12 21:13:25.643570+0800 ModuleProject[1815:57377] 任务1-异步任务执行-:2,thread:<NSThread: 0x60000215ecc0>{number = 4, name = (null)}
2020-08-12 21:13:25.643625+0800 ModuleProject[1815:57379] 任务2-异步任务执行-:2,thread:<NSThread: 0x600002129b00>{number = 3, name = (null)}
2020-08-12 21:13:25.643995+0800 ModuleProject[1815:57379] 全部任务执行完成,thread:<NSThread: 0x600002129b00>{number = 3, name = (null)}

5、信号量

dispatch_semaphore_create可以生成信号量,参数value是信号量计数的初始值;dispatch_semaphore_wait会让信号量值减一,当信号量值为0时会等待(直到超时),否则正常执行
dispatch_semaphore_signal会让信号量值加一,如果有通过dispatch_semaphore_wait函数等待Dispatch Semaphore的计数值增加的线程,会由系统唤醒最先等待的线程执行

  • 异步操作转换为同步
 - (void)semaphoreSync {
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 1、semaphore 初始创建时计数为 0。
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
    __block int number = 0;
    dispatch_async(queue, ^{
        // 追加任务 1
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
        
        number = 100;
        // 3、执行 dispatch_semaphore_signal 之后,总信号量加 1,此时 semaphore == 0,正在被阻塞的线程(主线程)恢复继续执行。
        dispatch_semaphore_signal(semaphore);
    });
    // 2、执行 dispatch_semaphore_wait 方法,semaphore 减 1,此时 semaphore == -1,当前线程进入等待状态。
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
	// 4、最后打印 semaphore---end,number = 100。
    NSLog(@"semaphore---end,number = %zd",number);
}
  • 为线程加锁

// 线程安全:使用 semaphore 加锁
- (void)initTicketStatusSave {
    _semaphoreLock = dispatch_semaphore_create(1);
    
    self.ticketSurplusCount = 10;
    
    // queue1 代表北京火车票售卖窗口
    dispatch_queue_t queue1 = dispatch_queue_create("net.bujige.testQueue1", DISPATCH_QUEUE_SERIAL);
    // queue2 代表上海火车票售卖窗口
    dispatch_queue_t queue2 = dispatch_queue_create("net.bujige.testQueue2", DISPATCH_QUEUE_SERIAL);
    
    __weak typeof(self) weakSelf = self;
    dispatch_async(queue1, ^{
        [weakSelf saleTicketSafe];
    });
    
    dispatch_async(queue2, ^{
        [weakSelf saleTicketSafe];
    });
}

/**
 * 售卖火车票(线程安全)
 */
- (void)saleTicketSafe {
    while (1) {
        // -1 相当于加锁
        dispatch_semaphore_wait(_semaphoreLock, DISPATCH_TIME_FOREVER);
        
        if (self.ticketSurplusCount > 0) {  // 如果还有票,继续售卖
            self.ticketSurplusCount--;
            NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%d 窗口:%@", self.ticketSurplusCount, [NSThread currentThread]]);
            [NSThread sleepForTimeInterval:0.2];
        } else { // 如果已卖完,关闭售票窗口
            NSLog(@"所有火车票均已售完");
            
            // 相当于解锁
            dispatch_semaphore_signal(_semaphoreLock);
            break;
        }
        
        // 相当于解锁
        dispatch_semaphore_signal(_semaphoreLock);
    }
}

打印结果
2020-08-12 21:50:36.752994+0800 ModuleProject[2266:81059] 剩余票数:9 窗口:<NSThread: 0x600002ebf940>{number = 4, name = (null)}
2020-08-12 21:50:36.957438+0800 ModuleProject[2266:81057] 剩余票数:8 窗口:<NSThread: 0x600002ed4700>{number = 5, name = (null)}
2020-08-12 21:50:37.162657+0800 ModuleProject[2266:81059] 剩余票数:7 窗口:<NSThread: 0x600002ebf940>{number = 4, name = (null)}
2020-08-12 21:50:37.367371+0800 ModuleProject[2266:81057] 剩余票数:6 窗口:<NSThread: 0x600002ed4700>{number = 5, name = (null)}
2020-08-12 21:50:37.571037+0800 ModuleProject[2266:81059] 剩余票数:5 窗口:<NSThread: 0x600002ebf940>{number = 4, name = (null)}
2020-08-12 21:50:37.774617+0800 ModuleProject[2266:81057] 剩余票数:4 窗口:<NSThread: 0x600002ed4700>{number = 5, name = (null)}
2020-08-12 21:50:37.975415+0800 ModuleProject[2266:81059] 剩余票数:3 窗口:<NSThread: 0x600002ebf940>{number = 4, name = (null)}
2020-08-12 21:50:38.179218+0800 ModuleProject[2266:81057] 剩余票数:2 窗口:<NSThread: 0x600002ed4700>{number = 5, name = (null)}
2020-08-12 21:50:38.383655+0800 ModuleProject[2266:81059] 剩余票数:1 窗口:<NSThread: 0x600002ebf940>{number = 4, name = (null)}
2020-08-12 21:50:38.583949+0800 ModuleProject[2266:81057] 剩余票数:0 窗口:<NSThread: 0x600002ed4700>{number = 5, name = (null)}
2020-08-12 21:50:38.788986+0800 ModuleProject[2266:81059] 所有火车票均已售完
2020-08-12 21:50:38.789250+0800 ModuleProject[2266:81057] 所有火车票均已售完

本文地址:https://blog.csdn.net/qq_32644987/article/details/107955594

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网