NSOperationQueue中的屏障操作 [英] Barrier operations in NSOperationQueue

查看:88
本文介绍了NSOperationQueue中的屏障操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

要求是,每当提交 barrier操作时,它都应等到之前提交的所有 non-barrier操作完成执行并阻止此后提交的其他操作. /p>

  • 无障碍操作应该能够同时执行.
  • 屏障操作应按顺序执行.

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

解决方案

这或多或少是 jeffamaphone 所说的,但我提出了一个要点,它应该大致按照您的要求做.

我创建了NSOperationQueueNSMutableArray,用作队列队列".每次添加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
}

一个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];
        }
    }
}

我可能错过了一些关键的事情.细节决定成败.

这闻起来有点像我的作业.如果是这样,请告诉我我获得的年级. :)


附录:通过 abhilash1912 的评论,它是一个不同但相似的 解决方案

This is more or less what jeffamaphone was saying, but I put up a gist that should, in rough outline, do what you ask.

I create a NSMutableArray of NSOperationQueues, which serves as a "queue of queues". Every time you add a BarrierOperation object, you tack a fresh suspended op queue on the end. That becomes the addingQueue, to which you add subsequent operations.

- (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
}

When one NSOperationQueue finishes, it gets popped and the next one starts running.

- (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];
        }
    }
}

I might have missed something crucial. The devil's in the details.

This smells a bit like a homework assignment to me. If so, tell me what grade I get. :)


Addendum: Via abhilash1912's comment, a different but similar approach. That code is tested, so it already wins. But it is a bit stale (2 years or so as of today; some deprecated method usage). Moreover, I question whether inheriting from NSOperationQueue is the best path, though it has the virtue of retaining familiarity. Regardless, if you've read this far, it's probably worth looking over.

If you create or find the world's greatest BarrierQueue class, please let us know in the comments or otherwise, so it can be linked up.

这篇关于NSOperationQueue中的屏障操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆