首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用NSRecursive锁等待操作完成

使用NSRecursive锁等待操作完成
EN

Stack Overflow用户
提问于 2011-03-30 12:17:55
回答 2查看 353关注 0票数 0

使用NSRecursiveLock有目的地等待后台线程上的操作完成会节省时间吗?下面是一个示例:

我有一个类,其中我希望拥有一个可以是异步或同步的loadParts函数。异步函数可能会被提前调用,以便可以在实际需要数据之前加载这些部分。同步应该检查数据是否已经加载,或者当前是否正在加载。如果它已经被加载,它可以只返回数据;如果它当前被加载,那么它应该等待它被加载,然后返回;如果它甚至没有被加载,那么它应该同步地加载它。这是我尝试使用的代码:

代码语言:javascript
复制
// Private function to be run either on main thread or
// background thread
-(void)_loadParts
{
    [_loadingPartsLock lock];
    _loadingParts = YES;

    // Do long loading operation

    _loadingParts = NO;
    _partsLoaded = YES;
    [_loadingPartsLock unlock];
}

// Asynchronous loading of parts
-(void)preloadParts
{
    if( _loadingParts || _partsLoaded )
        return;

    [self performSelectorInBackground:@selector(_loadParts) withObject:nil];
}

// Synchronous loading of parts
-(void)loadParts
{
    if( _loadingParts )
    {
        [_loadingPartsLock lock];
        [_loadingPartsLock unlock];
    }

    if( !_partsLoaded )
    {
         [self _loadParts];
    }
}

这是一种安全有效的方式吗?我已经看到了它可能存在的一些问题。在没有锁的情况下设置和测试BOOL的值是线程安全的吗?如果在后台线程仍在加载时调用同步函数,我还会在同步函数中锁定两次。

有没有更常见、更好的方法来实现这一功能?

谢谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-04-08 11:24:36

受bbum答案的启发,我找到了一个使用NSOperationQueue的解决方案,但并不完全像他所描述的那样。在我的preloadParts函数中,我创建并存储了一个load操作,它是运行我的后台线程函数的NSInvocationOperation实例。然后我将其添加到NSOperationQueue中。

如果在任何时候,数据被另一个类请求。我首先检查数据是否已加载(变量已设置)。如果没有,我检查操作是否在队列中。如果是,那么我调用_loadOperation waitUntilFinished。否则,我使用waitUntilFinished参数将其添加到操作队列中。这是我想出来的代码:

代码语言:javascript
复制
-(void)preloadCategories
{
    if( [[_operationQueue operations] containsObject:_loadOperation] )
        return;

    [_operationQueue addOperation:_loadOperation];
}

-(CCPart*)getCategoryForName:(NSString*)name
{
    if( nil == _parts )
    {
        [self loadCategories];
    }
    return [_parts objectForKey:name];
}

-(void)loadCategories
{
    if( nil != _parts )
        return;

    if( [[_operationQueue operations] containsObject:_loadOperation] )
    {
        [_loadOperation waitUntilFinished];
    }
    else
    {
        [_operationQueue addOperations:[NSArray arrayWithObject:_loadOperation]
                     waitUntilFinished:YES];
    }
}

-(void)_loadCategories
{
    // Function that actually does the loading and sets _parts to be an array of the data
    _parts = [NSArray array];
}

在初始化函数中,我将_operationQueue和_loadOperation设置如下:

代码语言:javascript
复制
_operationQueue = [[NSOperationQueue alloc] init];
            _loadOperation = [[NSInvocationOperation alloc] initWithTarget:self 
                                                                  selector:@selector(_loadCategories) 
                                                                    object:nil];
票数 0
EN

Stack Overflow用户

发布于 2011-03-30 12:30:14

一种远比这更好的解决方案是使用dispatch_queueNSOperationQueue (配置为串行操作)。

将您的加载操作排入队列,然后将完成时应该发生的任何操作排入队列。如果“完成”操作是“告诉主线程进行更新”,这很好--在主线程上执行一个方法,该方法实际上是一个触发更新以响应现在加载的数据的事件。

这完全避免了与锁定相关的问题和开销,同时还解决了“完成”通知问题,而不需要某种轮询机制。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5481805

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档