1、控制最大并发数

使用信号量可以设置最多有n条线程执行统一个任务,从而控制线程最大并发数:

  1. - (instancetype)init {
  2. if (self = [super init]) {
  3. // 设置最大并发数5
  4. self.semaphore = dispatch_semaphore_create(5);
  5. }
  6. return self;
  7. }
  8. - (void)otherTest {
  9. for (int i = 0; i < 20; i++) {
  10. [[[NSThread alloc] initWithTarget:self selector:@selector(test) object:nil] start];
  11. }
  12. }
  13. // 控制最大并发数
  14. - (void)test {
  15. // 开始等待
  16. dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
  17. sleep(2);
  18. NSLog(@"%s - %@",__func__, [NSThread currentThread]);
  19. // 等待结束
  20. dispatch_semaphore_signal(self.semaphore);
  21. }

2、信号量控制过程

wait方法:

  1. dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);

如果信号量的值 > 0,就让信号量的值减1,然后继续往下执行代码。
如果信号量饿值 <= 0,就会休眠等待,直到信号量的值大于零(等待时间由传入的时间参数决定),就让信号量的值减1,然后继续往下执行代码。
signal方法:

  1. dispatch_semaphore_signal(self.semaphore);

让信号量的值加1。

3、线程同步

如果将信号量的值设置为1,那么信号量也可以解决线程同步问题,保证同一时间只有一个线程执行任务:

  1. - (instancetype)init {
  2. if (self = [super init]) {
  3. // 设置最大并发数1
  4. self.ticketSemaphore = dispatch_semaphore_create(1);
  5. }
  6. return self;
  7. }
  8. // 线程同步
  9. - (void)__saleTicket {
  10. dispatch_semaphore_wait(self.ticketSemaphore, DISPATCH_TIME_FOREVER);
  11. [super __saleTicket];
  12. dispatch_semaphore_signal(self.ticketSemaphore);
  13. }

4、使用技巧

想要保证每个方法有一个信号量控制,可以在方法内部创建静态变量。

  1. - (void)test {
  2. static dispatch_semaphore_t semaphore;
  3. static dispatch_once_t onceToken;
  4. dispatch_once(&onceToken, ^{
  5. semaphore = dispatch_semaphore_create(1);
  6. });
  7. dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  8. // ......
  9. dispatch_semaphore_signal(semaphore);
  10. }

还可以把开始和结束宏定义,减少重复代码量:

  1. // 开始并等待
  2. #define SemaphonreBegin \
  3. static dispatch_semaphore_t semaphore; \
  4. static dispatch_once_t onceToken; \
  5. dispatch_once(&onceToken, ^{ \
  6. semaphore = dispatch_semaphore_create(1); \
  7. }); \
  8. dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  9. // 结束
  10. #define SemaphonreEnd \
  11. dispatch_semaphore_signal(semaphore);
  12. // 调用方法
  13. - (void)test3 {
  14. SemaphonreBegin;
  15. // ......
  16. SemaphonreEnd;
  17. }