2016-07-01 1 views
1

Quand je lance le code suivant plusieurs fois collisions appli à la ligne:mise à jour dispatch_async crash variable - sécurité des threads

res.append (i)

L'erreur est erreur fatale: UnsafeMutablePointer.destroy avec un nombre négatif ou pointeur étant libéré n'a pas été alloué *** mis un point d'arrêt dans malloc_error_break pour déboguer

est-il pas correct de mettre à jour une variable globale à l'intérieur dispatch_async?

classe ViewController: UIViewController {

var result = Array<Int>() 


func method(completion: (inner:() throws -> String)->Void){ 
    let group:dispatch_group_t = dispatch_group_create(); 
    let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 
    var res = Array<Int>() 
    for i in 0..<4 { 
     dispatch_group_async(group,queue){ 
      res.append(i) 
      print(res) 
      print("Block\(i)");     
      var s = 0 
      for k in 0..<1000 { 
       s = 2+3 
      } 
      print("Block\(i)End"); 



     } 
    } 

    dispatch_group_wait(group, DISPATCH_TIME_FOREVER); 

    print("All background tasks are done!!"); 
    print(res) 
} 


override func viewDidLoad() { 
    super.viewDidLoad() 


    self.method() { (inner:() throws -> String) -> Void in 
     do { 
      let res = try inner() 
      print(res) 
     } catch let error { 
      print(error) 
     } 
    } 
} 
+0

problème de base de multi-threading - à moins que mentionné spécifiquement Ne pas supposer qu'un objet est thread-safe et ne pas mettre à jour à partir de plusieurs threads –

Répondre

1

ouais, Array est pas thread-safe, donc quand écrire à un tableau, devrait assurer atomic.

Vous pouvez donc ajouter un verrou haute performance: dispatch_semaphore_t.

func method(completion: (inner:() throws -> String)->Void){ 
    // add lock 
    let lock: dispatch_semaphore_t = dispatch_semaphore_create(1) 
    let group:dispatch_group_t = dispatch_group_create(); 
    let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 
    var res = Array<Int>() 
    for i in 0 ..< 5 { 
     dispatch_group_async(group,queue){ 
      // lock 
      dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER) 
      res.append(i) 
      // unlock 
      dispatch_semaphore_signal(lock) 
      var s = 0 
      for k in 0..<1000 { 
       s = 2+3 
      } 
     } 
    } 

    dispatch_group_wait(group, DISPATCH_TIME_FOREVER); 

    print("All background tasks are done!!"); 
    print(res) 
} 

Mais attention, si votre tâche async est pas le fonctionnement du temps comme ci-dessus, ne pas utiliser multi-thread, car le calendrier de fil est temps et pourrait entraîner une perte de performance.

+0

Merci. C'était juste un exemple de code. Alors, si j'accède à beaucoup de variables globales à l'intérieur de dispatch_async, quelle est la meilleure option? Dois-je utiliser NSOperationQueue? – user584263

+0

Je ne sais pas si beaucoup de variables que vous mentionnez sont multi-threads. Sinon, il y a généralement deux types de traitement: 1. utiliser la file d'attente concurrente + le verrou comme ci-dessus 2. utiliser la file d'attente série peut aussi assurer atomique. Ou vous avez besoin d'utiliser un autre plan en fonction de votre demande. Vous pouvez lire cette série d'article https://www.raywenderlich.com/60749/grand-central-dispatch-in-depth-part-1, peut-être utile. – maquannene

+0

Et cette version Swift https://www.raywenderlich.com/79149/grand-central-dispatch-tutorial-swift-part-1 – maquannene