NSOperation

2019-09-30  本文已影响0人  Code_人生

一、start

- (void) start
{
  NSAutoreleasePool *pool = [NSAutoreleasePool new];
  double        prio = [NSThread  threadPriority];

  AUTORELEASE(RETAIN(self));    // Make sure we exist while running.
  [internal->lock lock];
  NS_DURING
    {
      if (YES == [self isExecuting])
    {
      [NSException raise: NSInvalidArgumentException
              format: @"[%@-%@] called on executing operation",
        NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
    }
      if (YES == [self isFinished])
    {
      [NSException raise: NSInvalidArgumentException
              format: @"[%@-%@] called on finished operation",
        NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
    }
      if (NO == [self isReady])
    {
      [NSException raise: NSInvalidArgumentException
              format: @"[%@-%@] called on operation which is not ready",
        NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
    }
      if (NO == internal->executing)
    {
      [self willChangeValueForKey: @"isExecuting"];
      internal->executing = YES;
      [self didChangeValueForKey: @"isExecuting"];
    }
    }
  NS_HANDLER
    {
      [internal->lock unlock];
      [localException raise];
    }
  NS_ENDHANDLER
  [internal->lock unlock];

  NS_DURING
    {
      if (NO == [self isCancelled])
    {
      [NSThread setThreadPriority: internal->threadPriority];
      [self main];
    }
    }
  NS_HANDLER
    {
      [NSThread setThreadPriority:  prio];
      [localException raise];
    }
  NS_ENDHANDLER;

  [self _finish];
  [pool release];
}

二、addDependency

- (void) addDependency: (NSOperation *)op
{
  if (NO == [op isKindOfClass: [NSOperation class]])
    {
      [NSException raise: NSInvalidArgumentException
          format: @"[%@-%@] dependency is not an NSOperation",
    NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
    }
  if (op == self)
    {
      [NSException raise: NSInvalidArgumentException
          format: @"[%@-%@] attempt to add dependency on self",
    NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
    }
  [internal->lock lock];
  if (internal->dependencies == nil)
    {
      internal->dependencies = [[NSMutableArray alloc] initWithCapacity: 5];
    }
  NS_DURING
    {
      if (NSNotFound == [internal->dependencies indexOfObjectIdenticalTo: op])
    {
      [self willChangeValueForKey: @"dependencies"];
          [internal->dependencies addObject: op];
      /* We only need to watch for changes if it's possible for them to
       * happen and make a difference.
       */
      if (NO == [op isFinished]
        && NO == [self isCancelled]
        && NO == [self isExecuting]
        && NO == [self isFinished])
        {
          /* Can change readiness if we are neither cancelled nor
           * executing nor finished.  So we need to observe for the
           * finish of the dependency.
           */
          [op addObserver: self
           forKeyPath: @"isFinished"
              options: NSKeyValueObservingOptionNew
              context: isFinishedCtxt];
          if (internal->ready == YES)
        {
          /* The new dependency stops us being ready ...
           * change state.
           */
          [self willChangeValueForKey: @"isReady"];
          internal->ready = NO;
          [self didChangeValueForKey: @"isReady"];
        }
        }
      [self didChangeValueForKey: @"dependencies"];
    }
    }
  NS_HANDLER
    {
      [internal->lock unlock];
      NSLog(@"Problem adding dependency: %@", localException);
      return;
    }
  NS_ENDHANDLER
  [internal->lock unlock];
}
- (void) observeValueForKeyPath: (NSString *)keyPath
               ofObject: (id)object
                         change: (NSDictionary *)change
                        context: (void *)context
{
  [internal->lock lock];

  /* We only observe isFinished changes, and we can remove self as an
   * observer once we know the operation has finished since it can never
   * become unfinished.
   */
  [object removeObserver: self forKeyPath: @"isFinished"];

  if (object == self)
    {
      /* We have finished and need to unlock the condition lock so that
       * any waiting thread can continue.
       */
      [internal->cond lock];
      [internal->cond unlockWithCondition: 1];
      [internal->lock unlock];
      return;
    }

  if (NO == internal->ready)
    {
      NSEnumerator  *en;
      NSOperation   *op;

      /* Some dependency has finished (or been removed) ...
       * so we need to check to see if we are now ready unless we know we are.
       * This is protected by locks so that an update due to an observed
       * change in one thread won't interrupt anything in another thread.
       */
      en = [internal->dependencies objectEnumerator];
      while ((op = [en nextObject]) != nil)
        {
          if (NO == [op isFinished])
        break;
        }
      if (op == nil)
    {
          [self willChangeValueForKey: @"isReady"];
      internal->ready = YES;
          [self didChangeValueForKey: @"isReady"];
    }
    }
  [internal->lock unlock];
}

三、addOperation

- (void) addOperation: (NSOperation *)op
{
  if (op == nil || NO == [op isKindOfClass: [NSOperation class]])
    {
      [NSException raise: NSInvalidArgumentException
          format: @"[%@-%@] object is not an NSOperation",
    NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
    }
  [internal->lock lock];
  if (NSNotFound == [internal->operations indexOfObjectIdenticalTo: op]
    && NO == [op isFinished])
    {
        //一个任务添加进来
      [op addObserver: self
       forKeyPath: @"isReady"
          options: NSKeyValueObservingOptionNew
          context: isReadyCtxt];
      [self willChangeValueForKey: @"operations"];
      [self willChangeValueForKey: @"operationCount"];
        //要执行的队列当中
      [internal->operations addObject: op];
      [self didChangeValueForKey: @"operationCount"];
      [self didChangeValueForKey: @"operations"];
      if (YES == [op isReady])
    {
        //更新状态
      [self observeValueForKeyPath: @"isReady"
                  ofObject: op
                change: nil
                   context: isReadyCtxt];
    }
    }
  [internal->lock unlock];
}
//多次回调
- (void) observeValueForKeyPath: (NSString *)keyPath
               ofObject: (id)object
                         change: (NSDictionary *)change
                        context: (void *)context
{
  /* We observe three properties in sequence ...
   * isReady (while we wait for an operation to be ready)
   * queuePriority (when priority of a ready operation may change)
   * isFinished (to see if an executing operation is over).
   */
  if (context == isFinishedCtxt)
    {
      [internal->lock lock];
        //正在执行的任务
      internal->executing--;
        //移除观察者
      [object removeObserver: self forKeyPath: @"isFinished"];
      [internal->lock unlock];
      [self willChangeValueForKey: @"operations"];
      [self willChangeValueForKey: @"operationCount"];
      [internal->lock lock];
        //执行完成的任务移除队列
      [internal->operations removeObjectIdenticalTo: object];
      [internal->lock unlock];
      [self didChangeValueForKey: @"operationCount"];
      [self didChangeValueForKey: @"operations"];
    }
  else if (context == queuePriorityCtxt || context == isReadyCtxt)
    {
      NSInteger pos;

      [internal->lock lock];
      if (context == queuePriorityCtxt)
        {
          [internal->waiting removeObjectIdenticalTo: object];
        }
      if (context == isReadyCtxt)
        {
          [object removeObserver: self forKeyPath: @"isReady"];
          [object addObserver: self
                   forKeyPath: @"queuePriority"
                      options: NSKeyValueObservingOptionNew
                      context: queuePriorityCtxt];
        }
        //如果当前任务就绪,按照优先级插入
      pos = [internal->waiting insertionPosition: object
                                   usingFunction: sortFunc
                                         context: 0];
      [internal->waiting insertObject: object atIndex: pos];
      [internal->lock unlock];
    }
  [self _execute];
}
- (void) _execute
{
  NSInteger max;

  [internal->lock lock];

  max = [self maxConcurrentOperationCount];
  if (NSOperationQueueDefaultMaxConcurrentOperationCount == max)
    {
      max = maxConcurrent;
    }

  NS_DURING
  while (NO == [self isSuspended]
    && max > internal->executing
    && [internal->waiting count] > 0)
    {
      NSOperation   *op;

      /* Take the first operation from the queue and start it executing.
       * We set ourselves up as an observer for the operating finishing
       * and we keep track of the count of operations we have started,
       * but the actual startup is left to the NSOperation -start method.
       */
      op = [internal->waiting objectAtIndex: 0];
      [internal->waiting removeObjectAtIndex: 0];
      [op removeObserver: self forKeyPath: @"queuePriority"];
      [op addObserver: self
       forKeyPath: @"isFinished"
          options: NSKeyValueObservingOptionNew
          context: isFinishedCtxt];
      internal->executing++;
        //isConcurrent 是否有并发的能力
      if (YES == [op isConcurrent])
    {
          [op start];
    }
      else
    {
      NSUInteger    pending;

      [internal->cond lock];
      pending = [internal->starting count];
      [internal->starting addObject: op];

      /* Create a new thread if all existing threads are busy and
       * we haven't reached the pool limit.
       */
      if (0 == internal->threadCount
        || (pending > 0 && internal->threadCount < POOL))
        {
          internal->threadCount++;
          [NSThread detachNewThreadSelector: @selector(_thread)
                       toTarget: self
                     withObject: nil];
        }
      /* Tell the thread pool that there is an operation to start.
       */
      [internal->cond unlockWithCondition: 1];
    }
    }
  NS_HANDLER
    {
      [internal->lock unlock];
      [localException raise];
    }
  NS_ENDHANDLER
  [internal->lock unlock];
}
上一篇下一篇

猜你喜欢

热点阅读