A non protetto incremento/decremento non è thread-safe - e quindi non atomico tra i thread. (Anche se potrebbe essere "atomica" wrt l'effettiva IL/ML trasformare .)
Questo codice di esempio LINQPad mostra risultati imprevedibili:
void Main()
{
int nWorkers = 10;
int nLoad = 200000;
int counter = nWorkers * nLoad;
List<Thread> threads = new List<Thread>();
for (var i = 0; i < nWorkers; i++) {
var th = new Thread((_) => {
for (var j = 0; j < nLoad; j++) {
counter--; // bad
}
});
th.Start();
threads.Add(th);
}
foreach (var w in threads) {
w.Join();
}
counter.Dump();
}
noti che la visibilità tra i thread è di importanza . La sincronizzazione garantisce questa visibilità oltre all'atomicità.
Questo codice è facilmente risolvibile, almeno nel contesto limitato presentato.Passare il decremento e osservare i risultati:
counter--; // bad
Interlocked.Decrement(ref counter); // good
lock (threads) { counter--; } // good
Anche quando si utilizza una variabile volatile
, i risultati sono ancora imprevedibili. Ciò sembra indicare che (almeno qui, quando l'ho appena eseguito) è anche non un operatore atomico come lettura/op/scrittura di thread in competizione erano interlacciati. Per vedere che il comportamento non è ancora corretta quando vengono rimossi problemi di visibilità (sono?), Aggiungere
class x {
public static volatile int counter;
}
e modificare il codice qui sopra per usare x.counter
al posto della variabile locale counter
.
La domanda migliore è probabile, è ciò che * utilizza * la concorrenza in idleAgents? – user2246674
possibile duplicato di [Il thread dell'operatore ++ è sicuro?] (Http://stackoverflow.com/questions/4628243/is-the-operator-thread-safe) – nawfal