Fix the deadlock by using the two different semaphore, the `@synchronized` can not represent two pointer array lock and may be entered twice

This commit is contained in:
DreamPiggy 2020-05-06 16:13:32 +08:00
parent 54771ceb22
commit fe730cc7e4
1 changed files with 41 additions and 26 deletions

View File

@ -20,6 +20,10 @@
atomic_flag _isAllFinished;
unsigned long _totalCount;
// Used to ensure NSPointerArray thread safe
dispatch_semaphore_t _prefetchOperationsLock;
dispatch_semaphore_t _loadOperationsLock;
}
@property (nonatomic, copy, readwrite) NSArray<NSURL *> *urls;
@ -106,7 +110,6 @@
}
- (void)startPrefetchWithToken:(SDWebImagePrefetchToken * _Nonnull)token {
NSPointerArray *operations = token.loadOperations;
for (NSURL *url in token.urls) {
@autoreleasepool {
@weakify(self);
@ -142,13 +145,13 @@
[asyncOperation complete];
}];
NSAssert(operation != nil, @"Operation should not be nil, [SDWebImageManager loadImageWithURL:options:context:progress:completed:] break prefetch logic");
@synchronized (token) {
[operations addPointer:(__bridge void *)operation];
}
SD_LOCK(token->_loadOperationsLock);
[token.loadOperations addPointer:(__bridge void *)operation];
SD_UNLOCK(token->_loadOperationsLock);
}];
@synchronized (token) {
[token.prefetchOperations addPointer:(__bridge void *)prefetchOperation];
}
SD_LOCK(token->_prefetchOperationsLock);
[token.prefetchOperations addPointer:(__bridge void *)prefetchOperation];
SD_UNLOCK(token->_prefetchOperationsLock);
[self.prefetchQueue addOperation:prefetchOperation];
}
}
@ -262,26 +265,38 @@
@implementation SDWebImagePrefetchToken
- (void)cancel {
@synchronized (self) {
[self.prefetchOperations compact];
for (id operation in self.prefetchOperations) {
id<SDWebImageOperation> strongOperation = operation;
if (strongOperation) {
[strongOperation cancel];
}
}
self.prefetchOperations.count = 0;
[self.loadOperations compact];
for (id operation in self.loadOperations) {
id<SDWebImageOperation> strongOperation = operation;
if (strongOperation) {
[strongOperation cancel];
}
}
self.loadOperations.count = 0;
- (instancetype)init {
self = [super init];
if (self) {
_prefetchOperationsLock = dispatch_semaphore_create(1);
_loadOperationsLock = dispatch_semaphore_create(1);
}
return self;
}
- (void)cancel {
SD_LOCK(_prefetchOperationsLock);
[self.prefetchOperations compact];
for (id operation in self.prefetchOperations) {
id<SDWebImageOperation> strongOperation = operation;
if (strongOperation) {
[strongOperation cancel];
}
}
self.prefetchOperations.count = 0;
SD_UNLOCK(_prefetchOperationsLock);
SD_LOCK(_loadOperationsLock);
[self.loadOperations compact];
for (id operation in self.loadOperations) {
id<SDWebImageOperation> strongOperation = operation;
if (strongOperation) {
[strongOperation cancel];
}
}
self.loadOperations.count = 0;
SD_UNLOCK(_loadOperationsLock);
self.completionBlock = nil;
self.progressBlock = nil;
[self.prefetcher removeRunningToken:self];