锁定对象不被多个线程访问 - Objective-C

cod*_*rer 36 multithreading objective-c ios

我对Objective-C中的线程安全性有疑问.我已经阅读了其他几个答案,一些Apple文档,但仍然对此有一些疑问,所以我想问我自己的问题.

我的问题有三个:

假设我有一个数组, NSMutableArray *myAwesomeArray;

折叠1:

现在纠正我,如果我错了,但从我的理解,使用@synchronized(myAwesomeArray){...}将阻止两个线程访问相同的代码块.所以,基本上,如果我有类似的东西:

-(void)doSomething {
    @synchronized(myAwesomeArray) {
        //some read/write operation on myAwesomeArray
    }
}
Run Code Online (Sandbox Code Playgroud)

那么,如果两个线程访问相同的方法相同的时间,代码块将是线程安全的.我猜我已经理解了这一部分.

折叠2:

如果myAwesomeArray被不同方法的多个线程访问,我该怎么办?如果我有类似的东西:

- (void)readFromArrayAccessedByThreadOne {
    //thread 1 reads from myAwesomeArray
}

- (void)writeToArrayAccessedByThreadTwo {
    //thread 2 writes to myAwesomeArray
}
Run Code Online (Sandbox Code Playgroud)

现在,两个方法同时由两个不同的线程访问.我如何确保myAwesomeArray不会出现问题?我是否使用类似NSLock或NSRecursiveLock的东西?

折3:

现在,在上面的两个案例中,myAwesomeArray是一个内存中的iVar.如果我有一个数据库文件,我并不总是留在内存中怎么办?databaseManagerInstance每当我想执行数据库操作时,我都会创建一个,并在完成后释放它.因此,基本上,不同的类可以访问数据库.每个类都创建自己的实例DatabaseManger,但基本上,它们都使用相同的单个数据库文件.在这种情况下,如何确保数据不会因竞争条件而损坏?

这将帮助我清除一些基本原理.

law*_*cko 43

折叠1 通常你对什么@synchronized是正确的理解.但是,从技术上讲,它不会使任何代码"线程安全".它可以防止不同的线程同时获取同一个锁,但是您需要确保在执行关键部分时始终使用相同的同步令牌.如果不这样做,您仍然可以发现自己处于两个线程同时执行关键部分的情况.检查文档.

折叠2 大多数人可能会建议你使用NSRecursiveLock.如果我是你,我会使用GCD.这是一个很好的文档,展示了如何从线程编程迁移到GCD编程,我认为这个问题的方法比基于NSLock的方法要好得多.简而言之,您创建一个串行队列并将任务分派到该队列中.这样,您可以确保关键部分是连续处理的,因此在任何给定时间只执行一个关键部分.

折叠3 这与折叠2相同,只是更具体.数据库是一种资源,通过许多方式它与数组或任何其他东西相同.如果要在数据库编程上下文中查看基于GCD的方法,请查看fmdb实现.它完全符合我在Fold2中描述的内容.

作为Fold 3的附注,我不认为每次想要使用数据库然后释放它时实例化DatabaseManager都是正确的方法.我认为你应该创建一个单一的数据库连接并通过你的应用程序会话保留它.这样就可以更轻松地进行管理.同样,fmdb是如何实现这一目标的一个很好的例子.

编辑 如果不想使用GCD,那么是的,你将需要使用某种锁定机制,是的,NSRecursiveLock如果你在方法中使用递归,将防止死锁,所以它是一个很好的选择(它被使用@synchronized).但是,可能有一个问题.如果许多线程可能等待相同的资源并且它们获取访问的顺序是相关的,那么这NSRecursiveLock是不够的.您可能仍然可以管理这种情况NSCondition,但相信我,在这种情况下,您将节省大量时间使用GCD.如果线程的顺序不相关,那么使用锁是安全的.


onm*_*133 5

正如斯威夫特3的斯威夫特3 WWDC 2016会话的会话720并发编程随着GCD,你应该使用queue

class MyObject {
  private let internalState: Int
  private let internalQueue: DispatchQueue

  var state: Int {
    get {
      return internalQueue.sync { internalState }
    }

    set (newValue) {
      internalQueue.sync { internalState = newValue }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)