集合在枚举时发生了变化 - 迭代时一切都是同步的,不会发生突变



我不是Objective C专家,问题发生在不是我编写的代码上。 但是,我做了研究,找不到我的问题可能的根本原因。 (我对Java和C/C++的多线程编程有很好的理解(。

下面是引发异常的代码的[模糊]版本(最终导致崩溃(:

@interface someInterface ()
@property (nonatomic) NSMutableArray *activeTokens;

下面的函数抛出异常:

@implementation someInterface
- (void)foo:(NSURL*)url headers:(NSDictionary*)headers
{
@synchronized (self.activeTokens) {
for (NSValue *object in self.activeTokens) {
X *tokenObject = object.nonretainedObjectValue;
if (tokenObject && [tokenObject.a.b isEqualToString:url.absoluteString]) {
tokenObject.x = [headers objectForKey:@"somekey"];
break;
}
}
}
}

访问集合的其他函数:

- (X*)bar:(NSURL*)url protocol:(NSString*)str 
{

X *token = [[X alloc] ...];
@synchronized (_activeTokens){
if (!_activeTokens) {
_activeTokens = [[NSMutableArray alloc] init];
}
NSValue *value = [NSValue valueWithNonretainedObject:token];
[_activeTokens addObject:value];
}
...
}

- (void)releaseToken:(X*)token
{
NSValue *value = [NSValue valueWithNonretainedObject:token];
@synchronized(_activeTokens) {
[_activeTokens removeObject:value];
}
}

- (X*)getRequestToken:(R*)request
{
@synchronized (self.activeTokens) {
for (NSValue *object in self.activeTokens) {
X *tokenObject = object.nonretainedObjectValue;
if (tokenObject && [tokenObject.a isEqualToString:[request.headers objectForKey:@"someKey"]]) {
return tokenObject;
}
}
}
return nil;
}
- (void)foooo:(BOOL)success reason:(NSString *)reason
{
if (!success)
{
@synchronized (self.activeTokens) {
for (NSValue *object in self.activeTokens) {
X *tokenObject = object.nonretainedObjectValue;
[tokenObject.s setR:reason];
}
}
}
}

我唯一能想到的是 activeToken 在同步时为零的情况 - 但我认为这应该不是问题,不是吗?

上级: 经过评论中的调查和对话,我认为唯一的情况实际上是当对象仍然为零时,因此不会发生同步。

以下是苹果公司实现的同步:

BREAKPOINT_FUNCTION(
void objc_sync_nil(void)
);

// Begin synchronizing on 'obj'. 
// Allocates recursive mutex associated with 'obj' if needed.
// Returns OBJC_SYNC_SUCCESS once lock is acquired.  
int objc_sync_enter(id obj)
{
int result = OBJC_SYNC_SUCCESS;
if (obj) {
SyncData* data = id2data(obj, ACQUIRE);
require_action_string(data != NULL, done, result = OBJC_SYNC_NOT_INITIALIZED, "id2data failed");
result = recursive_mutex_lock(&data->mutex);
require_noerr_string(result, done, "mutex_lock failed");
} else {
// @synchronized(nil) does nothing
if (DebugNilSync) {
_objc_inform("NIL SYNC DEBUG: @synchronized(nil); set a breakpoint on objc_sync_nil to debug");
}
objc_sync_nil();
}
done: 
return result;
}

我们可以看到,在 nil 上同步时没有任何反应。

我将数组的分配移动到初始值设定项。

"蛮力"解决方案是使用 ++ 方法进行迭代,即:

for (NSInteger i = 0; i < self.activeTokens.count; i++)
{
NSValue *object = [self.activeTokens objectAtIndex:i];
//...
}

问题是因为集合对象在开始时为 nil,并且分配是惰性的(第一次添加时(。这是错误的,因为 nil 上的同步不执行任何操作 - 请参阅问题中的更新。

最新更新