objective c - Bloquear un objeto para que no sea accedido por múltiples hilos-Objective-C




ios multithreading (2)

Al igual que en Swift 3 en la WWDC 2016 Session Session 720 Concurrent Programming With GCD en Swift 3 , debe usar la 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 }
    }
  }
}

Tengo una pregunta sobre seguridad de hilos en Objective-C. He leído un par de otras respuestas, alguna de la documentación de Apple, y todavía tengo algunas dudas con respecto a esto, así que pensé en hacer mi propia pregunta.

Mi pregunta es triple :

Supongamos que tengo una matriz, NSMutableArray *myAwesomeArray;

Fold 1:

Ahora @synchronized(myAwesomeArray){...} si me equivoco, pero por lo que entiendo, el uso de @synchronized(myAwesomeArray){...} evitará que dos subprocesos accedan al mismo bloque de código. Entonces, básicamente, si tengo algo como:

-(void)doSomething {
    @synchronized(myAwesomeArray) {
        //some read/write operation on myAwesomeArray
    }
}

luego, si dos subprocesos acceden al mismo método al mismo tiempo, ese bloque de código estará protegido contra subprocesos. Supongo que he entendido esta parte correctamente.

Fold 2:

¿Qué hago si myAwesomeArray está siendo accedido por múltiples hilos de diferentes métodos? Si tengo algo como:

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

- (void)writeToArrayAccessedByThreadTwo {
    //thread 2 writes to myAwesomeArray
}

Ahora, ambos métodos son accedidos por dos hilos diferentes al mismo tiempo. ¿Cómo me myAwesomeArray que myAwesomeArray no tenga problemas? ¿Utilizo algo como NSLock o NSRecursiveLock?

Fold 3:

Ahora, en los dos casos anteriores, myAwesomeArray era un iVar en la memoria. ¿Qué ocurre si tengo un archivo de base de datos que no siempre guardo en la memoria? Creo una databaseManagerInstance cada vez que quiero realizar operaciones de base de datos, y la libero una vez que he terminado. Por lo tanto, básicamente, diferentes clases pueden acceder a la base de datos. Cada clase crea su propia instancia de DatabaseManger , pero básicamente, todos usan el mismo archivo de base de datos. ¿Cómo me aseguro de que los datos no estén dañados debido a las condiciones de carrera en una situación así?

Esto me ayudará a aclarar algunos de mis fundamentos.


La subclase NSMutableArray proporciona bloqueo para los métodos de acceso (lectura y escritura). Algo como:

@interface MySafeMutableArray : NSMutableArray { NSRecursiveLock *lock; } @end

@implementation MySafeMutableArray

- (void)addObject:(id)obj {
  [self.lock lock];
  [super addObject: obj];
  [self.lock unlock];
}

// ...
@end

Este enfoque encapsula el bloqueo como parte de la matriz. Los usuarios no necesitan cambiar sus llamadas (pero deben tener en cuenta que podrían bloquear / esperar el acceso si el acceso es de tiempo crítico). Una ventaja importante de este enfoque es que si decide que prefiere no utilizar bloqueos, puede volver a implementar MySafeMutableArray para usar las colas de envío, o lo que sea mejor para su problema específico. Por ejemplo, podría implementar addObject como:

- (void)addObject:(id)obj {
    dispatch_sync (self.queue, ^{ [super addObject: obj] });
}

Nota: si usa bloqueos, seguramente necesitará NSRecursiveLock, no NSLock, porque no conoce las implementaciones de Objective-C de addObject, etc. son ellos mismos recursivos.





multithreading