iOS 大神之路多线程iOS学习

dispatch_semaphore GCD信号量

2016-12-02  本文已影响277人  小胡子杰克
dispatch_semaphore_create => 创建一个信号量

dispatch_semaphore_signal => 发送一个信号

dispatch_semaphore_wait => 等待信号

关于信号量,一般可以用停车来比喻。
  停车场剩余4个车位,那么即使同时来了四辆车也能停的下。如果此时来了五辆车,那么就有一辆需要等待。
  信号量的值就相当于剩余车位的数目,dispatch_semaphore_wait函数就相当于来了一辆车,dispatch_semaphore_signal 就相当于走了一辆车。停车位的剩余数目在初始化的时候就已经指明了(dispatch_semaphore_create(long value)),
  调用一次dispatch_semaphore_signal,剩余的车位就增加一个;调用一次dispatch_semaphore_wait剩余车位就减少一个;
  当剩余车位为0时,再来车(即调用dispatch_semaphore_wait)就只能等待。有可能同时有几辆车等待一个停车位。有些车主没有耐心,给自己设定了一段等待时间,这段时间内等不到停车位就走了,如果等到了就开进去停车。而有些车主就像把车停在这,所以就一直等下去。

代码示例:

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

NSLog(@"等待semaphore");

结果就是, 等待semaphore 这句话永远不会输出。原因有两个

  1. 你初始化信号量的时候,并没有库存,也就是你传入的值是0.
  2. 你传入等待增加库存的时间是 DISPATCH_TIME_FOREVER ,也就是说,除非有 地方运行了 dispatch_semaphore_signal 增加了库存,否则我永远等待下 去。 基于上述的两个原因,导致了程序不往下走了。

1.测试异步网络请求

在编写单元测试中就可以:

- (void)downloadImageURLWithString:(NSString *)URLString
{
// 1
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0)
    NSURL *url = [NSURL URLWithString:URLString];
    __unused Photo *photo = [[Photo alloc] initwithURL:url withCompletionBlock:^(UIImage *image, NSError *error) {
      if (error) {
            XCTFail(@"%@ failed. %@", URLString, error);
        }
// 2
      dispatch_semaphore_signal(semaphore);
    }];

// 3
      dispatch_time_t timeoutTime = dispatch_time(DISPATCH_TIME_NOW, 5);
      if (dispatch_semaphore_wait(semaphore, timeoutTime)) {
          XCTFail(@"%@ timed out", URLString);
        }
}

2.控制并发量

@implementation CustomOperationQueue

- (id)initWithConcurrentCount:(int)count
{
      self = [super init];
      if (self) {
        if (count < 1) count = 5;
        semaphore = dispatch_semaphore_create(count);
        queue = Dispatch_queue_create("Jake", DISPATCH_QUEUE_CONCURRENT);
      }
    return self;
}

- (id)init 
{
      return [self initWithConcurrentCount:5];
}

- (void)addTask:(CallBackBlock)block
{
    dispatch_async(queue, ^{
       dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
       dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), 0), ^{
            block();
            dispatch_semaphore_signal(semaphore);
        });
    });
}

@end

addTask:方法中
1.当前的初始库存为5
2.第一次调用dispatch_semaphore_wait的时候会直接执行下去,并减少一个库存。每当完成一个任务之后,会执行到dispatch_semaphore_signal将库存添加回去。
3.当执行的任务为非常耗时的操作的时候,库存不能及时地还回去。而dispatch_semaphore_wait在仍然执行,库存最后会被减到0,这样dispatch_semaphore_wait就只能进行等待直到前面的任务有执行完成将存库有添加回去为止。

如此便完成了并发量的控制!

线程锁的使用:
以下代码来自YYModel

+ (instancetype)classInfoWithClass:(Class)cls {
    if (!cls) return nil;
    static CFMutableDictionaryRef classCache;
    static CFMutableDictionaryRef metaCache;
    static dispatch_once_t onceToken;
    static dispatch_semaphore_t lock;
    dispatch_once(&onceToken, ^{
        classCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
        metaCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
        lock = dispatch_semaphore_create(1);
    });
    dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
    YYClassInfo *info = CFDictionaryGetValue(class_isMetaClass(cls) ? metaCache : classCache, (__bridge const void *)(cls));
    if (info && info->_needUpdate) {
        [info _update];
    }
    dispatch_semaphore_signal(lock);
    if (!info) {
        info = [[YYClassInfo alloc] initWithClass:cls];
        if (info) {
            dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
            CFDictionarySetValue(info.isMeta ? metaCache : classCache, (__bridge const void *)(cls), (__bridge const void *)(info));
            dispatch_semaphore_signal(lock);
        }
    }
    return info;
}
上一篇下一篇

猜你喜欢

热点阅读