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便能够发挥重大效果。