2015-04-22 7 views
12

Ho il codice seguente:C'è un modo di bloccare un oggetto in Swift come in C#

func foo() { 
    var sum = 0 
    var pendingElements = 10 

    for i in 0 ..< 10 { 
     proccessElementAsync(i) { value in 
      sum += value 
      pendingElements-- 

      if pendingElements == 0 { 
       println(sum) 
      } 
     } 
    } 
} 

In questo caso la funzione proccessElementAsync, come indica il nome, processo suo parametro di ingresso asincrono e quando finisce chiama il corrispondente gestore di completamento.

L'inconveniente di questo approccio è che poiché la variabile pendingElements è accessibile tramite più thread, è possibile che l'istruzione if pendingElements == 0 non abbia mai un valore true.

In C# siamo in grado di fare qualcosa di simile:

Object lockObject = new Object(); 
... 

lock (lockObject) { 
    pendingElements--; 

    if (pendingElements == 0) { 
     Console.WriteLine(sum); 
    } 
} 

e questo assicura che questa variabile sarà accessibile solo per un thread allo stesso tempo. C'è un modo per ottenere lo stesso comportamento in Swift?

+2

https://www.mikeash.com/pyblog/friday-qa-2015-02-06-locks-thread-safety-and-swift.html –

+0

Nota a margine: in C# 'blocco (someIntValue) 'non fa nulla lontanamente vicino a quello che stai cercando di ottenere ... In C# ti preghiamo di considerare le seguenti linee guida di default per creare oggetti speciali solo per bloccare ... –

+1

In C# saremo in grado di fare' Interlocked.Decrement' – Bas

risposta

11

Spero che questo ti possa aiutare.

func lock(obj: AnyObject, blk:() ->()) { 
    objc_sync_enter(obj) 
    blk() 
    objc_sync_exit(obj) 
} 

var pendingElements = 10 

func foo() { 
    var sum = 0 
    var pendingElements = 10 

    for i in 0 ..< 10 { 
     proccessElementAsync(i) { value in 

      lock(pendingElements) { 
       sum += value 
       pendingElements-- 

       if pendingElements == 0 { 
        println(sum) 
       } 
      } 

     } 
    } 
} 
+0

Grazie per la risposta. Se le chiamate objc_sync_enter (obj) e objc_sync_exit fanno ciò in cui credo, allora la tua risposta risolve il mio problema. Puoi aggiungere alla tua risposta alcuni dettagli su cosa fanno queste funzioni? Penso che questo migliorerà la qualità della risposta –

+0

Ho ottenuto le informazioni di objc_sync_enter e l'uscita dal documento di Apple. objc_sync_enter (id obj) : Iniziare la sincronizzazione su "obj". Assegna il pthread_mutex ricorsivo associato a 'obj' se necessario. int objc_sync_exit (id obj): Termina la sincronizzazione su "obj". –

+1

solo per gli altri, suggerirei una versione più robusta 'func synchronized (object: AnyObject!, @noescape _ chiusura:() genera ->()) {genera nuovamente objc_sync_enter (oggetto) defer { objc_sync_exit (oggetto) } chiusura prova()} ' –

4

Non ci sono strumenti di bloccaggio nativi, ma ci sono soluzioni alternative, come spiegato in questa domanda SO:

What is the Swift equivalent to Objective-C's "@synchronized"?

Usando una delle risposte, è possibile creare una funzione:

func synchronize(lockObj: AnyObject!, closure:()->()){ 
     objc_sync_enter(lockObj) 
     closure() 
     objc_sync_exit(lockObj) 
    } 

e quindi:

 func foo() { 
     var sum = 0 
     var pendingElements = 10 

     for i in 0 ..< 10 { 
      processElementAsync(i) { value in 

       synchronize(pendingElements) { 
        sum += value 
        pendingElements-- 

        if pendingElements == 0 { 
         println(sum) 
        } 
       } 

      } 
     } 
    } 
Problemi correlati