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