6
votes

Utilisation d'une utilisation en verrouillée

J'essaie d'écrire un programme multithreadé dans lequel chaque thread utiliserait un compteur puis d'incrémenter.

Par exemple: P>

System.Threading.Interlocked.Increment(counter);


5 commentaires

Quel problème spécifique avez-vous?


Si vous utilisez LOCK , vous n'avez pas besoin de Interlock.Increment. Quelle est votre question exactement?


Je me réfère à cet article: C-Sharpcorner.com/Uploadfile/maHesh / ...


Tant que «faire quelque chose avec le comptoir», il est en lecture seule, il n'y a pas de problème ici.


@HENKHOLTERMAN, cela dépend, si "lecture seule" signifie en lecture seule sur tous les threads, alors que vous êtes correct, si le compteur est un long exécuté sur une machine 32 bits, vous ne pouvez pas la lire en toute sécurité si D'autres threads pourraient mettre à jour la valeur. C'est la raison de Interverrouillé.Read


5 Réponses :


1
votes

Vous devrez protéger la lecture et l'écriture à l'aide de la serrure. Dans ce cas, l'instruction code> verrouillage code> fonctionne mieux et est la plus facile à suivre:

private int counter;
private readonly object locker = new object();

public void IncrementCounter()
{
    lock (this.locker)
    {
       this.counter++;
       Console.WriteLine(counter); 
    }
}

public int GetCounter()
{
    lock (this.locker)
    {
       return this.counter;
    }
}


0 commentaires

4
votes

Toutes les fonctions de verrouillage renvoient une copie de la valeur après modification, utilisée cette valeur renvoyée pendant votre thread.

var localCounter = System.Threading.Interlock.Increment(counter);


3 commentaires

Interlocked.Exchange et Interlocked.careExchange Remettez la valeur avant la modification (ils seraient inutiles si elles ont renvoyé la valeur «après»).


Vous avez raison. Je suppose que la leçon est Vérifiez toujours le MSDN


Incidemment, j'ai parfois souhaité pour interlocked.postincrement ou interlocked.postDecrementation , en particulier dans VB qui ne fonctionne pas une opération pratique "intégrée d'ajout / soustraction inteer". Fondamentalement, ils seraient la même opération que la normale interclocked.incrènement / décrément (avec une soustraction non cochée / Ajouter), mais si l'on veut la valeur de la variable avant le réglage, spécifiant que dans L'appel semblerait plus logique que de faire l'ajustement, puis de non modifier le résultat.



0
votes

Le interlocked.incrèce code> incrémente le compteur et renvoie sa valeur; Les deux opérations sont garanties pour être atomiques. Il existe d'autres fonctions verrouillées pour décrémenter / lire un compteur ou ajouter à / lire une variable. En général, on peut effectuer presque toutes les opérations simples sur un INT32 ou INT64 via le motif:

Int64 oldValue, newValue;
do
{
  oldValue = theVariable;
  newValue = oldValue | 1;  // Sample operation
} while (Interlocked.CompareExchange(theVariable, newValue, oldValue) != oldValue);


4 commentaires

Le retour de la valeur n'est pas garanti d'être atomique, seule la mise à jour de la variable transmise. Si un autre thread lisait la valeur de la variable qui a eu sa valeur définie du retour de la fonction alors qu'il était affecté, vous seriez déchiré. La valeur renvoyée est une copie locale sans fil non fil.


@Scottchamberlain: J'ai certainement 99.99999% de ce que foo = interlocked.incrèce (bar) effectuera une séquence atomique [TEMP = bar, Temp + = 1, bar = TEMP], suivie de manière non atomique par le Opération [FOO = TEMP]. La génération de la valeur de retour est garantie d'être atomique avec l'incrément, mais la fonction verrouillée doit être raisonnablement censée garantir quoi que ce soit sur l'atomicité de tout ce qui se passe après son retour < / i>.


Oui, mais votre réponse dit "les deux incrémentes le compteur et renvoie sa valeur; Les deux opérations sont garanties d'atomes. " Pour moi, vous impliquant l'affectation de FOO dans FOO = en verrouillée. Incrément (bar) serait atomique.


@Scottchamberlain: Désolé pour toute confusion. L'affiche originale suggère une séquence qui serait essentiellement "variable d'incrémentation atomique; lecture variable; stocker quelque part". Les deux premières étapes de cette séquence peuvent elles-mêmes être faites atomiquement, même si la troisième étape ne peut pas.



27
votes

Faire ceci est OK:

FLIVE A: STRAND> P>

lock (the_lock) {
   ++counter;
}


12 commentaires

-1 interlocked.incrèce prend un paramètre de référence et lit, incrémente et le stocke dans une seule opération atomique. var incrémented_counter = interlock.incrènement (compteur REF); est la version correcte.


@Aidiakapi Comment cela fait-il de ce que j'ai écrit incorrect? BTW, j'ai fait une faute de frappe: il devrait être Interverrouillé (pas Interlock ).


Les non de vos exemples compileront.


@Aidiakapi ahh ... j'ai oublié ref (édité). Mais d'autres ont fait la même erreur et je ne vois pas que vous descendez eux ! Dans tous les cas, il s'agit simplement d'une erreur de syntaxe et n'est pas vraiment pertinente pour le plus grand point que j'essayais de faire - ne pourriez-vous pas accepter que j'ai correctement illustré à la fois l'utilisation appropriée et inappropriée de diverses techniques de synchronisation?


Oui, mais l'autre raison que j'ai bownvote était parce que vous ne donnez que par exemple, disons quoi faire et ce que de ne pas faire, sans leur dire pourquoi c'est juste ou faux. Ne me trompez pas, vos exemples sont plus que corrects. Mais des choses comme: var incrémented_counter = interlocked.incrètent (Compteur Ref); pourrait impliquer à quelqu'un qui n'a aucune idée de ce que ce compteur n'est pas incrémenté et juste incrémenté_counter a été incrémenté. Mais je vais vous upvouver: p


Pourquoi le premier pas OK exemples n'est pas correct?


@ROYINAMIR car console.writeline (compteur) accède à "Naked" compteur . L'autre thread a peut-être modifié le entre cette ligne et la ligne précédente (alias. Condition de course), il n'y a pas de barrière de mémoire (normalement fournie par un verrou ou une opération verrouillée) pour vous assurer que Compteur n'est pas étalé (en raison de la mise en cache) et en fonction de son type et de l'architecture sous-jacente compteur pourrait ne pas être atomique du tout, vous pourriez donc accéder à des octets "à moitié cuites". Contraste que, au premier exemple "OK", où console.writeline (incrémented_counter) n'accède que la variable locale.


@Brankodimitrijevic Oh, vous voulez dire juste la console.writeline (comptoir); partie n'est pas OK ... non? Parce que les morceaux de moitié cuits .... non? (Je pensais qu'il y avait quelque chose qui ne va pas avec interlocked.incrèce (refontefe); elle-même (dans les deux threads)


@Royinamir à droite. Il ne peut jamais y avoir rien de "faux" avec les opérations ou sur des opérations imbriquées en isolement - elles fonctionnent toujours exactement comme elles le devraient. La difficulté d'écrire un code multi-threadé correct survient lorsque combine ces primitives ensemble ou avec le code "utile".


Pourquoi une réponse aussi difficile pour une question aussi simple? Je viens de demander si le problème (pour qu'il soit comme pas ok ) est la console.write partie ...


Pourquoi c'est un problème? interlocked.incrèce (compteur REF); Console.writeine ​​(comptoir); Si tel est le cas, comment résoudre un problème dans lequel je incrémente le compteur et ailleurs si vous devez comparer avec une sorte de si (compteur> n) ?


@Gianpierocaretti parce que interlocked.incrèce dans le fil b peut modifier compteur avant console.writeline dans le fil A. Pour l'autre question: Utilisez Verrouiller .



0
votes

Sur la question C'est une application de console, si certaines personnes essaient de porter sur les conseils ici à une application Windows, elles peuvent attraper des surprises, en particulier sur le mécanisme de verrouillage. Juste pour arriver à mon point: xxx

sur le code ci-dessus, GetVal dormira pendant 1 seconde. La plupart des gens penseront que le moniteur.frener empêchera le bloc de code à l'intérieur de l'instruction IF étant exécutée pendant que GetVal est toujours en 1 SEC de sommeil, mais si vous appuyez sur le bouton plusieurs fois dans une seconde, vous verrez la valeur TextBox11 Ce qui peut ne pas être l'intention que nous voulons de la base du code. Mais le comportement change si vous remplacez-vous à la place du verrouillage du moniteur: xxx

Vous verrez que le textebox1.text incrémentera uniquement par 1 même si vous appuyez sur le bouton A plusieurs fois (tandis que le getval est toujours en 1 seconde sommeil). Bloquant efficacement les déclarations à l'intérieur de la déclaration IF.


0 commentaires