【问题标题】:Not using NSLock correctly, but still seems to work没有正确使用 NSLock,但似乎仍然有效
【发布时间】:2013-10-27 09:45:09
【问题描述】:

我遇到了线程安全问题。我有一个队列,当我修改内容时会导致跨线程出错。我以前没有用过锁,但我想我试试。我在所有为我的队列操作支持 NSMutableArray 的代码周围添加了一个锁。我认为,问题在于我没有为所有人使用相同的锁。我在每个修改数组的方法中创建了一个新的 NSLock 实例。我假设我应该使用一个 NSLock ivar 来保护阵列。但我的困惑来自于我添加它后它就起作用了。下面是一个示例。我假设在任何地方我创建了一个新的 NSLock,我应该只使用一个 ivar NSLock。我认为这段代码只是将入队锁定在其他入队和出队对其他出队而不是入队对出队。澄清会很好。

@implmentation

...    

- (void)enqueue:(id)obj
{
  NSLock *arrayLock = [[NSLock alloc] init];
  [arrayLock lock];
   [_backingStore addObject:obj];
  [arrayLock unlock];
}

- (id)dequeue
{
  NSLock *arrayLock = [[NSLock alloc] init];
  [arrayLock lock];
  id result = [_backingStore firstObject];

  if( result )
  {
    [_backingStore removeObjectAtIndex:0];
  }

  [arrayLock unlock];
  return result;
}

...

@end

【问题讨论】:

    标签: objective-c cocoa thread-safety nslock


    【解决方案1】:

    是的,您确实需要使用相同的 NSLock 实例来锁定对数组的两次访问。与许多多线程错误一样,由于添加额外代码导致的时间差异,问题似乎已经消失。或者,可能只是你运气不好,第二次测试时没有出现问题。

    无论如何,NSLock 只是在 Objective-C 中锁定对关键部分的访问的一种方式。您也可以使用@synchronized(),从代码复杂性的角度来看这可能更容易:

    @synchronized(someSharedToken) {
        // Do your array access here
    }
    

    您还可以使用串行调度队列来序列化对资源的访问。这有几个优点,其中最重要的是能够将工作分派给它,而无需等待该工作在当前线程上完成。将工作分派到队列也比取出锁更便宜。请参阅 Apple 并发编程指南的 Creating Serial Dispatch Queues 部分。

    【讨论】:

    • 感谢您的回答。我计划移动到调度队列。我考虑过使用@synchronized,但认为它为异常处理带来了额外的开销。由于必须使用同一个实例,这是否意味着在我的示例中,如果两个线程调用 enqueue 方法,则实际上两者都不会阻塞另一个,因为每个方法调用都会创建自己的实例?
    • 是的。您可以通过我在这里放置的快速而肮脏的示例看到这一点:gist.github.com/armadsen/7045187
    • 感谢您的示例。
    猜你喜欢
    • 1970-01-01
    • 2015-09-10
    • 1970-01-01
    • 1970-01-01
    • 2011-11-13
    • 2014-01-25
    • 1970-01-01
    • 2010-09-08
    • 2016-12-26
    相关资源
    最近更新 更多