Una struttura dati utilizzata solo in un singolo thread è sempre sicura?

0

Ho avuto una conversazione con alcuni colleghi e il concetto di sicurezza del thread per una struttura dati è venuto fuori.

In questo esempio, abbiamo 2 thread: un thread principale e un thread in background.

Per la seguente pseudo classe:

class Foo {
  Array myArray;

  // Only ever called on the main thread
  // This method will call into the background thread
  // but when complete the onCompleteBlock will be called
  // on the main thread.
  function method1() {
    // do something to the array on main thread
    myArray.add('foo');
    callBackgroundThread(onComplete() {

       // onComplete callback is called on main thread
       // do something else to the array on the main thread
       myArray.add('bar');
    })
  }

  // only ever called on the main thread
  function method2() {
    // do some other stuff to the array on the main thread

    if (myArray.contains('bar') {
      myArray.remove('foo');
    }
  }
}

Quindi in questo esempio la classe ha una matrice come una struttura di dati. Entrambi i metodi sono sempre garantiti per essere richiamati sul thread principale. Method1 chiama una funzione che avvia un processo in background, quando il processo termina richiama nel thread principale.

Questa classe e la struttura dei dati di myArray sono "sicuri"?

So che questa classe non è thread-safe in quanto la struttura dei dati myArray non è protetta da alcuna sincronizzazione. Quindi se più thread chiamavano method1 e method avremmo avuto problemi. Ma ogni volta che viene utilizzato myArray, viene utilizzato sul thread principale.

  1. Un argomento sul perché questo potrebbe non essere sicuro è che se il thread principale è in pausa (come quando siamo nel thread in background), non può essere ripreso nello stesso punto in cui era stato interrotto, cioè forse un operazione chiamata method2 () ed è qui che il thread principale si riattiva e riprende.

  2. Un altro è che la memoria potrebbe essere stata scambiata. Non sono sicuro di cosa si intendesse per questo.

Per essere onesti, non ho compreso appieno entrambe le argomentazioni e ho pensato che questa classe andava bene poiché tutte le variabili erano accessibili solo sul thread principale. Se uno dei due argomenti sopra è vero, qualcuno può aiutare a spiegare ulteriormente? Ho pensato che assicurarmi di modificare i dati sullo stesso thread sarebbe sicuro.

    
posta lostintranslation 19.04.2017 - 04:03
fonte

3 risposte

6

Se una struttura dati è protetta da un errore o meno è inerente al suo design, non al modo in cui viene utilizzata. Quindi, a meno che la tua classe, che avvolge una infrastruttura non sicura, possa di per sé garantire l'integrità delle sue strutture interne, anch'essa non è sicura.

L'utilizzo di una struttura non sicura all'interno di un singolo thread non rende sicura la struttura dati, ma è che la utilizza in modo sicuro. Semantica.

I due argomenti che hai presentato sono assurdi a meno che non si programmi esclusivamente per computer Packard Bell a 233 MHz o qualcosa di altrettanto terribile.

  1. Sospendere e riprendere i thread, per quanto riguarda il flusso di esecuzione, è un processo essenzialmente trasparente. Se i thread riprendessero in posti apparentemente casuali, come potresti far funzionare qualcosa in modo affidabile? Se un thread viene messo in pausa poco prima di inizializzare alcune variabili, e riprende in un secondo momento dove vengono utilizzate le variabili, il programma sta per esplodere.
  2. Sostanzialmente lo stesso accordo di prima. Se il sistema operativo decide di mescolare casualmente lo spazio di memoria, come farai a fare qualcosa?

Comunque il problema della sicurezza del thread entra in gioco solo quando si hanno più thread all'interno di un singolo processo.

    
risposta data 19.04.2017 - 04:37
fonte
1

Dato questo:

  1. Array non è una struttura di dati thread-safe
  2. I metodi di myArray vengono chiamati sempre solo dai metodi di Foo o dai callback creati da Foo
  3. I metodi di Foo e i callback creati vengono eseguiti solo nella discussione principale
  4. tutti i metodi Array conserva Array invarianti di classe
  5. Foo ha la proprietà di tutti gli oggetti contenuti in myArray , e può darli in lease ai thread in background

Quindi quello che stai facendo qui deve anche preservare l'invariante di classe di Array . In altre parole, non entrerai in situazioni come, per esempio, myArray pensa di avere quattro oggetti nei suoi campi di lunghezza interna ma in realtà hanno solo tre oggetti validi nella memoria effettiva, oppure inserisci Foo con myArray nel mezzo di spostare i suoi oggetti interni intorno. Nella parola @ whatsisname, stai utilizzando myArray in sicurezza.

Tuttavia, potrebbe non necessariamente preservare invariante di classe di Foo . Attualmente, questo è indecidibile perché non hai presentato abbastanza contesto per me per determinare le invarianti di Foo .

Potrebbe anche non preservare necessariamente l'invariante degli oggetti contenuti nella matrice. Se myArray contiene solo dati immutabili o di sola lettura, allora è banale concludere che gli oggetti sono anche sicuri; ma se myArray può contenere dati mutabili, e il thread in background può mutare gli oggetti, quindi determinare se ciò che fai qui è sicuro è più complicato, dovrai fare un'analisi della proprietà per assicurarti che tutti i dati mutabili ci siano solo in leasing su un thread alla volta (o se gli oggetti possono essere affittati a più thread o che sincronizzano i loro accessi)

    
risposta data 19.04.2017 - 17:21
fonte
0

Le strutture dati sicure vengono fornite con sovraccarico poiché l'utilizzo deve essere sincronizzato in modo che solo un thread muti i dati alla volta. Anche l'accesso in lettura potrebbe essere necessario sincronizzarlo.

I thread di dati locali non devono essere thread-safe in quanto non vi è alcuna contesa sul thread per l'uso dei dati. L'accesso a questi dati è sicuro, ma non sicuro. In genere è meglio evitare oggetti thread-safe per i dati locali se è disponibile un'alternativa non thread-safe. Ciò eviterà inutilmente la sincronizzazione dell'accesso.

Esistono tecniche per due thread per accedere in modo sicuro a determinati tipi di strutture di dati senza sincronizzazione. Ciò richiede chiare responsabilità per i dati. Un uso per questa tecnica sarebbe mantenere un buffer circolare di elementi di lavoro passati da un thread all'altro.

    
risposta data 21.04.2017 - 05:24
fonte

Leggi altre domande sui tag