2017-05-16 2 views
0

Je souhaite appeler le code suivant à partir de plusieurs threads.Rendre le thread de code sûr sans utiliser l'instruction lock

// x is a global/member and initialized to 0 
if (Interlocked.Increment(ref x) == 2) 
{ 
    // do something only once 
} 

Ceci est bien sûr pas thread-safe: si, au moment de l'exécution du premier filet est arrêté après x a été incrémentée mais avant l'évaluation, puis le second incréments de fil x il est donc maintenant 2, l'instruction if est true. Ensuite, nous revenons au premier thread et il devient également vrai dans l'instruction if.

Cela peut être résolu en entourant le code par l'instruction lock.

Existe-t-il un moyen de sécuriser les threads sans utiliser l'instruction lock?

+2

Votre scénario décrit ne se produira pas car la valeur de retour de la méthode 'Interlocked.Increment()' ne peut pas être modifiée par d'autres threads. – dymanoid

+0

Votre code * peut être dangereux s'il accède plus tard à 'x' et suppose qu'il est le même que le résultat de l'incrément, mais vous n'avez pas montré de code ici qui démontre ce problème. –

Répondre

2

Ceci est bien sûr pas sûre car si au moment de l'exécution du premier fil est arrêté après x était incrémenté mais avant l'évaluation. Ensuite, le deuxième thread incrémente et x est connu 2 donc l'instruction if est vraie. Ensuite, nous revenons au premier thread et il est également vrai.

Ceci n'est pas vrai.

Interlocked.Increment est une opération atomique aucun lock supplémentaire n'est requis. (sinon quel devrait être le point de cela?)

La valeur est incrémentée et vous obtenez la valeur incrémentée. Même si une autre augmentation s'est produite après, vous avez toujours la première valeur incrémentée. donc le si va évaluer à faux.

Votre code d'ailleurs est thread-safe.

0

Je pense que vous avez tort dans votre hypothèse. La valeur de retour à partir de Interlocked.Increment est la valeur après l'incrément, pas la valeur de x au moment de l'évaluation. Il est tout à fait possible que x aurait pu être modifié par un autre fil, de sorte que le suivant serait vrai:

int x = 1; 
var y = Interlocked.Increment(ref x); 

if(x!=y)