2015-08-01 3 views
5

Ho letto un sacco di discussioni ed esempi su come rendere una proprietà protetta da un thread. C'è uno sulla pagina per this threadsafe wrapper classChe cosa è non sicuro su una semplice proprietà impostata in C#?

L'esempio dato è questo:

internal class MyThreadSafeCass 
{ 
    // *** Lock *** 
    private object PropertyLock = new object(); 

    // *** Property *** 
    private int m_Property = 0; 

    // *** Thread-safe access to Property using locking *** 
    internal int Property 
    { 
     get 
     { 
      lock (PropertyLock) 
      { 
       return m_Property; 
      } 
     } 
     set 
     { 
      lock (PropertyLock) 
      { 
       m_Property = value; 
      } 
     } 
    } 
} 

È chiaro quello che sta succedendo qui, e che cosa stanno facendo le serrature, ma sto lottando per capire perché è necessario . Perché è il seguente non thread safe? Cosa può andare storto?

internal class MyThreadSafeCass 
{ 
    // *** Property *** 
    private int m_Property = 0; 

    // *** Thread-safe access to Property using locking *** 
    internal int Property 
    { 
     get 
     { 
      return m_Property; 
     } 
     set 
     { 
      m_Property = value; 
     } 
    } 
} 
+0

Due thread (o più) non possono accedere alla memoria allo stesso tempo. Con il secondo campione, se due thread accedono contemporaneamente alla variabile, viene generata un'eccezione AccessViolationException. Con il "lock" (o usando l'oggetto Monitor) costringi il secondo thread ad aspettare che il primo thread finisca il suo lavoro. senza violazione. – Yanos

+0

Leggi questo articolo: http://blog.coverity.com/2014/03/12/can-skip-lock-reading-integer/#.VbyOn63EpYQ – Enigmativity

+1

No, non viene generata una 'AccessViolationException' se due thread tentano di accedere a una posizione di memoria nello stesso momento. – user12864

risposta

0

@Enigmativity ottiene i complimenti qui (se non i punti, purtroppo) per il collegamento a this blog about skipping locks, che a sua volta link a this blog about CPU reordering optimizations, che è la vera carne della risposta.

In sintesi, le CPU possono (e fanno) applicare ottimizzazioni al codice che comportano la modifica dell'ordine in cui vengono eseguite le letture/scritture. Queste modifiche sono garantite per essere coerenti e impercettibili all'interno del thread in cui vengono eseguite. Tuttavia, non (non possono) garantire la coerenza tra più thread che accedono alla memoria condivisa. Il blocco, come mostrato nell'esempio nella domanda iniziale, impone restrizioni all'accesso a questa memoria condivisa che ripristina la coerenza.

Come ho detto, questo è un riassunto. Non posso aggiungere nulla alla descrizione nei blog collegati sopra, quindi rinvierebbe chiunque fosse interessato a conoscere la risposta completa per seguire quei collegamenti.

@Enigmativity, lo accetterò ancora come risposta da parte tua se lo pubblichi come tale. Altrimenti, accetterò questa risposta e la chiuderò.

0

un'espressione come: m_Property ++; in più di un thread, il parallelo restituisce valori diversi. Soprattutto su cpu multi core.

  • Il vecchio valore viene caricato nella cache della CPU.
  • Il valore verrà incrementato dalla CPU
  • Il nuovo valore verrà salvato nella memoria.

Esempio:

  • nucleo uno caricherà valore 10
  • nucleo due caricherà valore 10 allo stesso tempo come nucleo uno
  • sia aggiungere uno (valore è 11)
  • sia salverà i dati alla memoria
  • il risultato sarà 11.
  • ma ci si aspetta 12

Vedi this per ulteriori dettagli

+0

Non risponde alla domanda, perché questo problema non è risolto da nessuna delle classi date. In entrambi i casi l'esecuzione di 'obj.Property ++' comporta simultaneamente risultati imprevisti. – Dzienny

+0

E il lucchetto non farà esattamente nulla per prevenire la condizione di gara descritta qui. – Voo