iOS Dispatch Semaphore使用

Dispatch Semaphore介绍

Dispatch Semaphore 是持有计数的信号,是多线程编程中的计数类类型信号。所谓信号,即类似于小区出入口的栅栏。可通过时举起栅栏,不可通过时候放下栅栏。Dispatch Semaphore 中,使用计数来实现该功能。计数为0时等待,计数为1或大于1时,减去1而不等待。

使用方法

下面是创建一个dispatch_semaphore_t 对象,参数表示计数的初始值,下面例子初始化值为1。从dispatch_semaphore_create方法名可看出,该函数与 dispatch_group_t和 dispatch_queue_t一样,在非ARC模式下必须通过dispatch_release函数释放。也可以使用 dispatch_retain函数持有。

 dispatch_semaphore_t semaphore_t=dispatch_semaphore_create(1);
复制代码

dispatch_semaphore_wait 函数等待 dispatch_semaphore_t 的计数值大于或等于1。当计数值大于等于1,或者在待机中计数值大于等于1时,对计数进行减法操作并从 dispatch_semaphore_wait函数返回。 第二个参数和 dispatch_group_wait一样,由dispatch_time_t 类型值指定等待时间。本例中的参数值意味着永久等待。 dispatch_semaphore_wait和dispatch_group_wait 函数的返回值也一样。

 dispatch_semaphore_wait(semaphore_t, DISPATCH_TIME_FOREVER);
复制代码

dispatch_semaphore_wait 函数返回0时,可安全执行所需的排他控制的处理。等处理结束时,通过dispatch_semaphore_signal函数将 dispatch_semaphore_t 的计数值加1。

使用案例

//创建队列
dispatch_queue_t queue =dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//创建dispatch_semaphore_t 信号对象,并设置计数初始化值为1
    dispatch_semaphore_t semaphore_t=dispatch_semaphore_create(1);
    NSMutableArray *array=[[NSMutableArray alloc]init];
    for (int i=0; i<50000; i++) {
        dispatch_async(queue, ^{
          //等待semaphore_t,直到 semaphore_t 计数值大于等于1,目的保证可访问array对象的线程同时只有1个
            dispatch_semaphore_wait(semaphore_t, DISPATCH_TIME_FOREVER);
          //因semaphore_t 大于等于1,所以将semaphore_t计数值减去1,dispatch_semaphore_wait执行返回。到此,dispatch_semaphore_t 的计数值恒为0。可以安全的进行array 数据更新
            [array addObject:@(i)];
          //排他控制处理结束,dispatch_semaphore_signal 将semaphore_t 的计数值加1。
          //等待dispatch_semaphore_t 的计数值增加的线程,就由最先等待的线程执行。
            dispatch_semaphore_signal(semaphore_t);
        });
    }
复制代码

dispatch_semaphore_t 死锁问题改进

例:死锁


  dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_queue_t queue=dispatch_queue_create("111111", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"b1 %@", [NSThread currentThread]);
        [self getUserDepartmentWithSemaphore:semaphore];
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    dispatch_async(queue, ^{
        NSLog(@"b2 %@", [NSThread currentThread]);
        [self getMyDepartmentListWithSemaphore:semaphore];
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    dispatch_async(queue, ^{
      
        if (self.myDepartment!=nil) {
            [[NSOperationQueue mainQueue]addOperationWithBlock:^{
            self.selectedDepartment=self.myDepartment;
                self.companyFileHeaderView.title=self.selectedDepartment.name;
            }];
            [self loadNewData];
        }
        dispatch_semaphore_signal(semaphore);
        NSLog(@"b3 %@", [NSThread currentThread]);
    });

2021-04-23 18:09:05.509692+0800 IQHIPan[15507:322370] b1 <NSThread: 0x6000027f01c0>{number = 7, name = (null)}
复制代码

例:改进后

 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_queue_t queue=dispatch_queue_create("111111", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"b1 %@", [NSThread currentThread]);
        [self getUserDepartmentWithSemaphore:semaphore];
    });
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"b2 %@", [NSThread currentThread]);
        [self getMyDepartmentListWithSemaphore:semaphore];
    });
   
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        if (self.myDepartment!=nil) {
            [[NSOperationQueue mainQueue]addOperationWithBlock:^{
            self.selectedDepartment=self.myDepartment;
                self.companyFileHeaderView.title=self.selectedDepartment.name;
            }];
            [self loadNewData];
        }
        dispatch_semaphore_signal(semaphore);
        NSLog(@"b3 %@", [NSThread currentThread]);
    });

返回结果
2021-04-23 18:11:21.149867+0800 IQHIPan[15592:324628] b1 <NSThread: 0x600003d1c200>{number = 5, name = (null)}
2021-04-23 18:11:21.445690+0800 IQHIPan[15592:324628] b2 <NSThread: 0x600003d1c200>{number = 5, name = (null)}
2021-04-23 18:11:21.775718+0800 IQHIPan[15592:324628] b3 <NSThread: 0x600003d1c200>{number = 5, name = (null)}
复制代码

总结

在没有Serial Dispatch Queue 和dispatch_barrier_async 函数那么大粒度且一部分处理需要进行排他控制情况下,dispatch_semaphore便可以发挥重大作用。

Guess you like

Origin juejin.im/post/7054422405606801445