dispatch_semaphore

参考文章在GCD中,我们通常使用dispatch_semaphore来处理并发控制,
semaphore主要有三个函数操作分别是:

dispatch_semaphore_create    //创建semaphore,此时可以传入一个初始的信号量值

dispatch_semaphore_signal     //发送一个信号,当信号量被发送后,semaphore中的计数会加1

dispatch_semaphore_wait      // 等待信号,会使semaphore的计数减1,当semaphore中的计数小于0时,线程会被阻塞,直至计数大于0

总结就是dispatch_semaphore_signal发送一个信号,使得信号总量加1,dispatch_semaphore_wait等待信号,当信号总量小于0时会一直等待,否则可以正常运行并让信号量减1,
dispatch_group_t group = dispatch_group_create();
dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
for(in i = 0; i < 100; i++) {
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
dispatch_group_async(group,queue,^{
NSLog(@"%i",i);
sleep(2);
dispatch_semaphore_signal(semaphore);
});
}
dispatch_group_wait(group,DISPATCH_TIME_FOREVER);

当初始化时设置信号量为1时就可以当做资源锁来使用.在没有等待情况出现时,其性能比OSSpinLock自旋锁还要高。但是一旦有等待情况出现时,其性能会下降很多。
+ (nullable instancetype)classInfoWithClass:(Class)cls {
//1.类缓存
static CFMutableDictionaryRef classCache;
//2.资源锁
static dispatch_semaphore_t lock;
//3.创建单例
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
classCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
lock = dispatch_semaphore_create(1);
});
//4.加锁并取出缓存的类信息
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
XRClassInfo info = CFDictionaryGetValue(classCache, (__bridge const void )(cls));
dispatch_semaphore_signal(lock);
//5.如果没有缓存的类信息,则需要重新创建,并缓存
if(!info) {
//6.根据类,创建新的类信息
info = [[XRClassInfo alloc] initWithClass:cls];
if(info) {
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
CFDictionarySetValue(classCache, (bridge const void *)(cls), (bridge const void *)(info));
dispatch_semaphore_signal(lock);
}
}
return info;
}

欢迎大家关注我的微信公众号

wechat.jpg
<think>我们正在讨论GCD中的dispatch_semaphore_wait函数。根据引用内容,我们可以总结如下: 1. **信号量的基本概念**:信号量(Semaphore)是一种用于控制多线程并发访问资源的同步机制。它通过一个计数器来控制同时访问资源的线程数量(引用[5])。 2. **GCD信号量的API**: - `dispatch_semaphore_create(value)`:创建一个信号量,参数`value`表示初始信号量的值(即可用资源的数量,引用[3])。 - `dispatch_semaphore_wait(semaphore, timeout)`:等待信号量。如果信号量的值大于0,则减1并继续执行;否则,线程将阻塞等待直到信号量变为正数或超时(引用[3][5])。 - `dispatch_semaphore_signal(semaphore)`:发送信号量,将信号量的值加1。如果有线程在等待,则唤醒其中一个(引用[3])。 3. **使用注意事项**: - `dispatch_semaphore_wait`和`dispatch_semaphore_signal`必须成对出现(引用[3])。 - 在多个异步任务中,通常将`wait`放在异步任务的第一行,而将`signal`放在任务完成的地方(引用[4])。 - 在主线程中调用`dispatch_semaphore_wait`且等待时间为`DISPATCH_TIME_FOREVER`(永久等待)可能导致主线程卡死(引用[2])。 4. **使用示例**: - 控制最大并发数:创建一个初始值为N的信号量,每次执行任务前`wait`,任务完成后`signal`,这样最多同时有N个任务执行。 - 同步任务:将信号量初始值设为0,在需要等待异步任务完成时调用`wait`,在异步任务完成后调用`signal`。 下面是一个使用信号量控制并发和同步的示例代码: **示例1:控制最大并发数(例如最多同时执行2个任务)** ```objective-c dispatch_semaphore_t sem = dispatch_semaphore_create(2); // 允许同时执行2个任务 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); for (int i = 0; i < 10; i++) { dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); // 等待信号量,如果信号量>0则减1,否则阻塞 dispatch_async(queue, ^{ // 执行任务 NSLog(@"任务%d开始", i); sleep(1); // 模拟耗时操作 NSLog(@"任务%d结束", i); dispatch_semaphore_signal(sem); // 任务完成,信号量加1 }); } ``` **示例2:等待异步任务完成(同步多个异步任务)** ```objective-c dispatch_semaphore_t sem = dispatch_semaphore_create(0); dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ // 模拟异步任务 sleep(2); NSLog(@"异步任务完成"); dispatch_semaphore_signal(sem); // 任务完成,发送信号 }); // 主线程等待异步任务完成 dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); NSLog(@"继续执行"); ``` 注意:在第二个示例中,如果在主线程中调用`dispatch_semaphore_wait`,且异步任务没有及时完成,会导致主线程卡死(引用[2])。因此,在主线程中使用信号量等待需要谨慎,最好设置超时时间。 **总结使用步骤**: 1. 创建信号量:`dispatch_semaphore_create(初始值)` 2. 在需要等待资源的地方调用`dispatch_semaphore_wait` 3. 在资源使用完毕或任务完成时调用`dispatch_semaphore_signal` 4. 注意避免在主线程永久等待(使用`DISPATCH_TIME_FOREVER`)以免卡死界面。 希望以上介绍对您有所帮助。 §§相关问题§§ 1. 为什么在主线程使用`dispatch_semaphore_wait`可能导致卡死? 2. 如何用信号量实现线程安全的数据访问? 3. 信号量与互斥锁(mutex)有什么区别? 4. 除了控制并发和同步,信号量还有哪些应用场景? </think> ### dispatch_semaphore_wait 使用指南 `dispatch_semaphore_wait` 是 GCD(Grand Central Dispatch)中用于线程同步的关键函数,基于经典的信号量(Semaphore)机制实现资源访问控制。以下是详细解析: #### 一、核心作用 1. **线程同步**:控制多线程对共享资源的访问顺序(引用[3][5]) 2. **资源计数**:通过信号量值限制同时访问资源的线程数量 3. **任务协调**:实现异步任务的同步等待(引用[1][4]) #### 二、API 组成 ```objective-c // 创建信号量(value:初始可用资源数) dispatch_semaphore_t sem = dispatch_semaphore_create(1); // 等待信号量(阻塞当前线程直到资源可用) dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); // 释放信号量(资源使用完毕时调用) dispatch_semaphore_signal(sem); ``` > 注意:`wait`和`signal`必须成对出现(引用[3]) #### 三、使用场景与示例 1. **控制最大并发数**(限制同时执行的任务数) ```objective-c // 限制最多3个并发任务 dispatch_semaphore_t sem = dispatch_semaphore_create(3); for (int i=0; i<10; i++) { dispatch_async(queue, ^{ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); // 获取资源 // 执行耗时任务(如网络请求) [self downloadImage:i completion:^{ dispatch_semaphore_signal(sem); // 释放资源 }]; }); } ``` 2. **同步异步任务**(等待多个任务完成) ```objective-c dispatch_semaphore_t sem = dispatch_semaphore_create(0); // 任务1(异步) dispatch_async(queue1, ^{ [self loadData]; dispatch_semaphore_signal(sem); }); // 任务2(异步) dispatch_async(queue2, ^{ [self processImage]; dispatch_semaphore_signal(sem); }); // 主线程等待两个任务完成 dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); NSLog(@"所有任务完成"); ``` #### 四、关键注意事项 1. **死锁风险**: - 主线程调用 `DISPATCH_TIME_FOREVER` 会导致界面卡死(引用[2]) - 解决方案:设置超时时间 `dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC);` 2. **执行顺序**: - 多个 `wait` 调用顺序不影响功能(引用[1]) - 但建议将 `wait` 放在异步任务开始处(引用[4]) 3. **信号量值**: - 初始值=1:实现互斥锁(Mutex)效果 - 初始值=N:控制N个并发资源 - 初始值=0:用作任务完成标志 #### 五、工作原理 1. 当 `wait` 被调用时: - 信号量值 >0:值减1立即返回 - 信号量值=0:线程阻塞等待(引用[5]) 2. 当 `signal` 被调用时: - 唤醒一个等待线程 - 信号量值加1 > 经典 PV 操作:`wait` 对应 P 操作(申请资源),`signal` 对应 V 操作(释放资源)(引用[5])
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值