随便说说
其实GCD大家都有接触过,也不在解释GCD是什么,为什么突然想说信号量问题,最近这几次面试,当我问到面试者怎么处理多个请求完成后的一系列操作时,有的说造一个临时变量的做追加,其实这样可以,也算是信号量的基本逻辑,有的说用线程做延时操作,怎么延时,怎么操作说的不清楚,有少部分会提到GCD信号量,但是可能说不出来怎么操作,通过信号量的增加与递减,进行网络的并发请求,最后再做网络请求完成后的最终处理;其实实际上大家在做的时候,在网上一搜,基本都能找到;
GCD信号量的应用场景,一般是控制最大并发量,控制资源的同步访问,如数据访问,网络同步加载等
简单聊聊
///创建 dispatch_semaphore_create() ///增加 dispatch_semaphore_signal() ///减去 dispatch_semaphore_wait()
下面用简单的栗子模拟多个网络请求,再进行最终的操作
//创建信号量 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); //创建队列 dispatch_queue_t queue = dispatch_get_global_queue(0, 0); //创建线程组 dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, queue, ^{ NSLog(@"第一个网络请求"); dispatch_semaphore_signal(semaphore); }); dispatch_group_async(group, queue, ^{ NSLog(@"第二个网络请求"); dispatch_semaphore_signal(semaphore); }); dispatch_group_async(group, queue, ^{ NSLog(@"第三个网络请求"); dispatch_semaphore_signal(semaphore); }); dispatch_group_notify(group, queue, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"三个请求完成后执行"); });
信号量是用于多线程同步的,跟锁不一样的是,信号量不一定是锁定某一个资源,而是流程上的概念,比如:有A、B两个线程,B线程要等A线程完成某一任务以后再进行自己下面的步骤,这个任务 并不一定是锁定某一资源,其实还可以是进行一些计算或者数据处理之类;
下面再通过做一个基于 NSObject 的生产者、消费者的 XKGradeRoom 工作间,看下信号量的用法,我们可以给生产间定一个最大生产量(这里定2个),毕竟生产间也不能无限制的生产,通过生产者与消费者关系,合理的对生产间的产量进行把控,在产量达到最大产量时,就停止生产,等待消费者消费。
XKGradeRoom.h
#import <Foundation/Foundation.h> /** 生产消费工作间 */ @interface XKGradeRoom : NSObject /** 生产 */ - (void)xk_produce:(NSString *)sp; /** 消费 @return NSString */ - (NSString*)xk_comsumer; @end
XKGradeRoom.m
#import "XKGradeRoom.h" @interface XKGradeRoom() /** 仓库 */ @property(strong,nonatomic) NSMutableArray* baseArray; /** 访问仓库(临界区)的互斥访问信号量 */ @property(strong,nonatomic) dispatch_semaphore_t criticalSemaphore; /** 消费者-是否消费仓库对象的标记 */ @property(strong,nonatomic) dispatch_semaphore_t comsumerSemaphore; /** 生产者-是否生产对象的标记 */ @property(strong,nonatomic) dispatch_semaphore_t productSemaphore; /** 仓库装载最大量 */ @property(nonatomic,assign) int maxProductCount; @end @implementation XKGradeRoom - (instancetype)init{ self = [super init]; if (self) { [self setup]; } return self; } - (void)setup{ _maxProductCount = 2; self.baseArray = [NSMutableArray array]; self.productSemaphore = dispatch_semaphore_create(_maxProductCount); self.comsumerSemaphore = dispatch_semaphore_create(0); //初始化临界区互斥访问信号量,用信号量实现互斥,特殊初始值为1. //控制同一时刻只有一个线程对象在访问仓库 self.criticalSemaphore = dispatch_semaphore_create(1); } /** 生产 */ -(void)xk_produce:(NSString *)sp{ //先获取访问仓库的信号量 long baseCount = dispatch_semaphore_wait(self.criticalSemaphore, 5 * NSEC_PER_SEC); if(baseCount != 0){ NSLog(@"仓库有人正在使用,生产者处于等待"); }else{ //再判断 仓库是否还有可放物品的空间 long maxSpaceCount = dispatch_semaphore_wait(self.productSemaphore, 5 * NSEC_PER_SEC); if(maxSpaceCount != 0){ NSLog(@"仓库%d个空间已经使用完,生产者处于等待:仓库容量:%lu",_maxProductCount,[self.baseArray count]); //生产完了释放临界区的访问锁 dispatch_semaphore_signal(self.criticalSemaphore); }else{ [self.baseArray addObject:sp]; NSLog(@"新生产一个,仓库目前有:%lu",[self.baseArray count]); dispatch_semaphore_signal(self.criticalSemaphore); dispatch_semaphore_signal(self.comsumerSemaphore); } } } /** 消费 @return NSString */ -(NSString*)xk_comsumer{ NSString* e = nil; long baseCount = dispatch_semaphore_wait(self.criticalSemaphore, 5 * NSEC_PER_SEC); //先获取访问仓库的信号量 if(baseCount != 0){ NSLog(@"仓库有人正在使用,消费者处于等待"); }else{ //再判断 仓库是否还有可取,如果有物品,则取一个出来,否则t等待 long avableCount = dispatch_semaphore_wait(self.comsumerSemaphore, 5 * NSEC_PER_SEC); if(avableCount != 0){ NSLog(@"空仓,消费者处于等待"); //生产完了释放临界区的访问锁 dispatch_semaphore_signal(self.criticalSemaphore); }else{ e = [self.baseArray objectAtIndex:[self.baseArray count] -1]; [self.baseArray removeLastObject]; NSLog(@"消费了:%@ 仓库还有%lu:",e,[self.baseArray count]); //生产完了释放临界区的访问锁 dispatch_semaphore_signal(self.criticalSemaphore); //将仓库中的可放置的数量 +1 dispatch_semaphore_signal(self.productSemaphore); } } return e; } @end
下面测试下这个工作间
XKGradeRoom * gradeRoom = [XKGradeRoom new]; //创建一个myDispatchQueue,主要是用于防止资源的竞争,一个线程处使用完资源,然后另外一个才能继续使用 dispatch_queue_t myDispatchQueue = dispatch_queue_create("com.example.gcd,myDispatchQueue", NULL); dispatch_async(myDispatchQueue, ^{ [gradeRoom xk_produce:@"Queue1"]; NSLog(@"Queue1-执行完毕"); }); dispatch_async(myDispatchQueue, ^{ [gradeRoom xk_comsumer]; NSLog(@"Queue2-执行完毕"); }); dispatch_async(myDispatchQueue, ^{ [gradeRoom xk_comsumer]; NSLog(@"Queue3-执行完毕"); }); dispatch_async(myDispatchQueue, ^{ [gradeRoom xk_produce:@"Queue4"]; NSLog(@"Queue4-执行完毕"); }); dispatch_async(myDispatchQueue, ^{ [gradeRoom xk_produce:@"Queue5"]; NSLog(@"Queue5-执行完毕"); }); dispatch_async(myDispatchQueue, ^{ [gradeRoom xk_produce:@"Queue6"]; NSLog(@"Queue6-执行完毕"); }); dispatch_async(myDispatchQueue, ^{ [gradeRoom xk_comsumer]; [gradeRoom xk_comsumer]; [gradeRoom xk_comsumer]; [gradeRoom xk_comsumer]; NSLog(@"Queue7-执行完毕"); });
打印结果:
来源:https://www.cnblogs.com/wangkejia/p/12600352.html