NSOperationQueue中的障碍操作

The*_*eer 6 objective-c nsoperationqueue grand-central-dispatch barrier

我们如何dispatch_barrier_async使用NSOperationQueue或基于任何用户定义的数据结构实现等效行为NSOperationQueue

要求是,无论何时提交屏障操作,它都应该等到之前提交的所有非屏障操作完成执行并阻止之后提交的其他操作.

  • 非屏障操作应该能够同时执行.
  • 屏障操作应该连续执行.

注意:不使用GCD,因为它不提供(或至少很难)对操作的大量访问,例如取消单个操作等.

i_a*_*orf 5

创建一个NSOperation障碍,然后使用

- (void)addDependency:(NSOperation *)operation
Run Code Online (Sandbox Code Playgroud)

使该屏障操作依赖于您想要在其之前进行的所有操作。


Cla*_*ges 4

这或多或少是jeffamaphone所说的,但我提出了一个要点,粗略地说,应该按照你的要求去做。

我创建了一个NSMutableArrayof NSOperationQueues,它充当“队列的队列”。每次添加对象时,都会在末尾BarrierOperation添加一个新的暂停操作队列。这将成为addingQueue,您可以在其中添加后续操作。

- (void)addOperation:(NSOperation *)op {
    @synchronized (self) {
        if ([op isKindOfClass:[BarrierOperation class]]) {
            [self addBarrierOperation:(id)op];
        } else {
            [[self addingQueue] addOperation:op];
        }
    }
}

// call only from @synchronized block in -addOperation:
- (void)addBarrierOperation:(BarrierOperation *)barrierOp {
    [[self addingQueue] setSuspended:YES];

    for (NSOperation *op in [[self addingQueue] operations]) {
        [barrierOp addDependency:op];
    }

    [[self addingQueue] addOperation:barrierOp];

    // if you are free to set barrierOp.completionBlock, you could skip popCallback and do that

    __block typeof(self) weakSelf = self;
    NSOperation *popCallback = [NSBlockOperation blockOperationWithBlock:^{
        [weakSelf popQueue];
    }];
    [popCallback addDependency:barrierOp];
    [[self addingQueue] addOperation:popCallback];
    [[self addingQueue] setSuspended:NO];

    NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
    [opQueue setSuspended:YES];

    [_queueOfQueues addObject:opQueue]; // fresh empty queue to add to
}
Run Code Online (Sandbox Code Playgroud)

当一个NSOperationQueue完成后,它会被弹出,下一个开始运行。

- (void)popQueue
{
    @synchronized (self) {
        NSAssert([_queueOfQueues count], @"should always be one to pop");
        [_queueOfQueues removeObjectAtIndex:0];

        if ([_queueOfQueues count]) {
            // first queue is always running, all others suspended
            [(NSOperationQueue *)_queueOfQueues[0] setSuspended:NO];
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我可能错过了一些重要的事情。细节决定成败。

这对我来说有点像家庭作业。如果是这样,请告诉我我得到了多少分。:)


附录:通过abhilash1912的评论,一种不同但相似的方法。该代码已经过测试,因此它已经获胜。但它有点陈旧(截至今天大约有 2 年;一些已弃用的方法使用)。此外,我质疑继承是否NSOperationQueue是最好的路径,尽管它具有保持熟悉的优点。无论如何,如果您已经读到这里,那么它可能值得一看。

如果您创建或找到世界上最伟大的 BarrierQueue 类,请在评论或其他方式中告诉我们,以便将其链接起来。