一、创建信号量 保证关键代码段不被并发调用。
@interface SDWebImageManager ()
@property (strong, nonatomic, readwrite, nonnull) SDImageCache *imageCache;
@property (strong, nonatomic, readwrite, nonnull) id<SDImageLoader> imageLoader;
@property (strong, nonatomic, nonnull) NSMutableSet<NSURL *> *failedURLs;
@property (strong, nonatomic, nonnull) dispatch_semaphore_t failedURLsLock; // a lock to keep the access to `failedURLs` thread-safe
@property (strong, nonatomic, nonnull) NSMutableSet<SDWebImageCombinedOperation *> *runningOperations;
@property (strong, nonatomic, nonnull) dispatch_semaphore_t runningOperationsLock; // a lock to keep the access to `runningOperations` thread-safe
@end
_runningOperationsLock = dispatch_semaphore_create(1);
如果 value > 0
,就相当于创建了个信号量,并同时发出value个信号。
如果 value = 0
,就相当于单纯仅仅创建了个信号量,还没发信号。
如果 value < 0
,直接failure,返回一个NULL。
二、线程安全操作加锁
- (void)safelyRemoveOperationFromRunning:(nullable SDWebImageCombinedOperation*)operation {
if (!operation) {
return;
}
SD_LOCK(self.runningOperationsLock);
[self.runningOperations removeObject:operation];
SD_UNLOCK(self.runningOperationsLock);
}
#ifndef SD_LOCK
#define SD_LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
#endif
#ifndef SD_UNLOCK
#define SD_UNLOCK(lock) dispatch_semaphore_signal(lock);
#endif
等待信号量:dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER)
传入所要等待信号的信号量。dispatch_semaphore_t
的信号计数-1。 超时等待时间。超过该时间就返回非0,并会直接往下执行。
也可以设置为DISPATCH_TIME_FOREVER
,永久等待。
发送信号量:dispatch_semaphore_signal(lock);
传入所要发送信号的信号量。dispatch_semaphore_t的信号计数+1。
三、信号量的应用
在多线程并发的场景,通过控制信号量来保证操作的同步。
- (void)testFunc{
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"任务1:%@",[NSThread currentThread]);
dispatch_semaphore_signal(sem);
});
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"任务2:%@",[NSThread currentThread]);
dispatch_semaphore_signal(sem);
});
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"任务3:%@",[NSThread currentThread]);
});
}
2021-05-12 11:08:27.074869+0800 learnDISsemaphore[1412:64135] 任务1:<NSThread: 0x600002051a40>{number = 6, name = (null)}
2021-05-12 11:08:27.075174+0800 learnDISsemaphore[1412:64135] 任务2:<NSThread: 0x600002051a40>{number = 6, name = (null)}
2021-05-12 11:08:27.075358+0800 learnDISsemaphore[1412:64135] 任务3:<NSThread: 0x600002051a40>{number = 6, name = (null)}