0
votes

Un verrou est-il obligatoire lors de l'utilisation de tâches?

Je développe actuellement une application dans WinForm C # pour afficher les valeurs d'un périphérique, mais je dois trouver le bon chemin.

Je démarre une tâche qui est une boucle sans fin dans le constructeur Mainform . Cette tâche lit les données d'un appareil et les écrit dans des variables partagées.

Mainform lit ces variables partagées pour afficher les données.

Comme la tâche est écrire uniquement et Mainform lit uniquement les variables partagées. Dois-je utiliser l'instruction de verrouillage sur les variables partagées? Quel est le risque si vous n'utilisez pas Lock?

Voici le début de la tâche dans le constructeur Mainform .

Merci!

Task.Run(() =>
{
    while (true)
    {
        try
        {
            ReadDeviceData();
        }
        catch (Exception e)
        {
            Dispatcher.CurrentDispatcher.Invoke(() => 
                MessageBox.Show(e.Message +"\n\n"+ e.StackTrace, "task exception\n"));
        }                        

        Thread.Sleep(200);
    }
});


2 commentaires

La sécurité des threads est un sujet énorme et vous devrez commencer à rechercher. si vous pouviez affiner ce que vous lisez et écrivez, cela vous aiderait à vous donner une réponse ... en bref, si partagé, ce n'est pas atomique ou immuable, ce n'est pas thread-safe ou vous avez peur des valeurs périmées, un verrou est probablement ce dont vous avez besoin


Vous rencontrez un certain nombre de problèmes avec ce code. Exécuter une boucle while (true) dans une tâche n'est pas une bonne façon de procéder. Ni l'un ni l'autre ne se contente d'attraper chaque exception. L'appel de Thread.Sleep (200) est généralement mauvais. Et enfin, ReadDeviceData () doit mettre à jour l'interface utilisateur à partir d'un thread non-UI, ce qui ne devrait pas être fait. Nous sommes heureux de vous aider à corriger votre code, mais vous devriez publier un exemple minimal reproductible afin que nous puissions reproduire ce vous voyez en étant capable d'exécuter votre code.


4 Réponses :


0
votes

Si un seul thread écrit dans la variable, vous n'avez pas à verrouiller. Le verrouillage est recommandé lorsque vous essayez d'écrire simultanément dans une variable.

https://docs.microsoft .com / fr-fr / dotnet / csharp / language-reference / keywords / lock-statement


0 commentaires

0
votes

Cela dépend de ReadDeviceData .

La lecture de int , bool ou object ('s reference) est en sécurité dans le modèle de mémoire de C #.

Dans d'autres cas, vous pouvez envisager d'utiliser ReaderWriterLock ou ReaderWriterLock qui est plus adapté à votre situation.


0 commentaires

0
votes

Le mot-clé lock ne verrouille pas les variables. Il définit une portion de code qui ne peut être exécutée que sur un thread à la fois. Par exemple, de ces deux blocs de code, un seul pourrait être en cours d'exécution à tout moment, et seulement sur un thread:

var results = new SomeClass
{
    A = random.Next(),
    B = random.Next()
};
results.C = results.A + results.B;
this.LatestResults = results;

Donc à un moment donné, un seul thread est en lecture ou en les variables membres A, B et C.

Que se passerait-il si nous supprimions les verrous? Le système d'exploitation utilise le multithreading préventif, vous ne pouvez donc pas vous assurer que votre code ne sera pas interrompu à tout moment, entre deux lignes de code (et parfois même pendant une). Ainsi, le deuxième bloc de code, par exemple, pourrait se produire entre deux lignes quelconques du premier bloc de code. Voyons voir ...

this.A = random.Next();
this.B = random.Next();
Console.WriteLine("{0}+{1}={2}", this.A, this.B, this.C);
this.C = this.A + this.B;

Comme vous pouvez le voir clairement, ce programme serait mauvais en maths.

Cela étant dit, nous pouvons atténuer le problème sans aucun verrou en étant intelligent sur la façon dont nous attribuons les choses.

lock (lockObject)
{
    this.A = random.Next();
    this.B = random.Next();
    this.C = this.A + this.B;
}

lock (lockObject)
{
    Console.WriteLine("{0}+{1}={2}", this.A, this.B, this.C);
}

Désormais, la seule variable partagée (puisque chaque thread obtient ses propres variables locales) est LatestResults . Qui peut être mis à jour en une seule opération atomique. Dans ce cas, aucun verrou n'est requis.


0 commentaires

0
votes

Vous devez toujours verrouiller lors de la lecture et de l'écriture sur des données partagées, sauf si vous êtes un expert en programmation multithread sans verrouillage, auquel cas vous ne devriez pas poser cette question. Le filetage sans verrou comporte de nombreuses mises en garde, et il vaut mieux prévenir que guérir.

Gardez à l'esprit que les serrures incontestées sont bon marché. Vous pouvez verrouiller un million de fois en une seconde et votre processeur ne le remarquera même pas. Les écluses deviennent un goulot d'étranglement lorsqu'elles sont contestées. Si votre interface utilisateur accède aux données partagées de manière sporadique et non dans une boucle serrée, vous ne devriez avoir aucun problème à utiliser les verrous. Aucune raison de rechercher une solution sans verrouillage dans ce cas.


0 commentaires