随便说说
其实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