在OSSpinLockLock中使用willChangeValueForKey / didChangeValueForKey

时间:2012-08-29 18:05:43

标签: objective-c ios5 grand-central-dispatch

我想在所有4个不同的线程完成工作时发出通知。我保留了总线程的数量,并且有一个监听器在线程完成时做了一些工作。

以下是一种安全的方法吗?

// ivars:
NSMutableArray *list;
OSSpinLock lock;

#define MAX_ALLOWED 4

- (void)someThreadedWork
{
    // Iterate thru 4 different items using gcd and update
    for (int x = 0; x < MAX_ALLOWED; ++x)
    {
        dispatch_async(some_queue, ^{
           // Do some work.. once done, 
           [self updateCount:ix];
        });
    }
}

- (void)updateCount:(NSInteger)newCount
    OSSpinLockLock(&lock);
    {
        [list addObject:[NSNumber numberWithInt:newCount]];

        if ([list count] == MAX_ALLOWED)
        {
            _allValuesUpdatedAt = [NSDate date];
        }
    }
    OSSpinLockUnlock(&lock);
}

- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object 
change:(NSDictionary*)change context:(void*)context 
{
    // When I get the 'allItemsUpdatedAt' event, I will perform some other work
}

- (id)init {
    if (self = [super init])
    {
        // there is a corresponding removeObserver in the dealloc
        list = [[NSMutableArray alloc] init];
        [anInstance addObserver:self 
                forKeyPath:@"allItemsUpdatedAt" 
                options:NSKeyValueObservingOptionNew 
                context:NULL];
    }
    return self;
}

2 个答案:

答案 0 :(得分:1)

HachiEthan关于dispatch_async的评论完全正确。如果您使用dispatch_group_async,那么您根本不需要任何锁定,也不必跟踪当前正在运行的线程。它会为你做所有这些。

请参阅“并发编程指南”中的"Waiting on Groups of Queued Tasks",以获得更快,更简单,更强大且能耗更低的方法来解决此问题。另请参阅同一文档中的“从线程迁移”以了解如何将基于线程的系统转换为基于队列的系统。

答案 1 :(得分:0)

以下是一些事情:

红旗:您更改了锁内_allValuesUpdatedAt的值,但可能会在其他位置“读取”其值...(例如,任何人都在观察属性{{1}除非你的allValuesUpdatedAt属性也受同一个allValuesUpdatedAt实例的保护,否则你会遇到问题。 (编辑:同样,你的上面的代码没有保留NSDate,所以它会在某个时候自动释放。)

如果您使用&lock并将其传递给串行队列,则您不需要使用自旋锁来更新dispatch_async中的值,前提是{ {1}}方法仅由从该串行队列运行的代码访问。 (注意:您仍然需要保护对list

的访问权限

如果需要从其他代码(例如主线程)访问updateCount:,那么是的,您将需要某种锁定,就像您拥有的那样。


编辑:保留你拥有的大部分内容,但要解决红旗问题

allValuesUpdatedAt