web-dev-qa-db-fra.com

C # et thread-safety d'un bool

Je suis très confus à ce sujet - si la lecture/le basculement d'une valeur booléenne est thread-safe.

    // case one, nothing
    private bool v1;
    public bool V1 { get { return v1; } set { v1 = value; } }

    // case two, with Interlocked on set
    private int v2;
    public int V2 { get { return v2; } set { Interlocked.Exchange(ref v2, value); } }

    // case three, with lock on set
    private object fieldLock = new object();
    private bool v3;
    public bool V3 { get { return v3; } set { lock (fieldLock) v3 = value; } }

Sont-ils tous thread-safe?

[~ # ~] modifier [~ # ~]

D'après ce que j'ai lu ( cliquez ) l'atomicité de bool ne garantit pas qu'il sera thread-safe. Est-ce que volatile saisira de l'aide?

18

Non, tous ne sont pas thread-safe.

Le premier cas n'est pas complètement sûr pour les threads, ou mieux dit - ce n'est pas du tout sûr pour les threads. Même si les opérations avec booléen sont atomiques, la valeur variable peut être stockée dans un cache, et donc, comme dans le processeur multicœur, chaque cœur possède son propre cache, la valeur peut être potentiellement corrompue.

Pour aller encore plus loin, le compilateur et le processeur peuvent effectuer certaines optimisations internes, y compris la réorganisation des instructions, ce qui peut nuire à la logique de votre programme.

Vous pouvez ajouter le mot clé volatile pour informer le compilateur que ce champ est utilisé dans un contexte multithread. Il résoudra les problèmes de réordonnancement du cache et des instructions, mais ne vous donnera pas vraiment de code "thread safe" (car les opérations d'écriture ne seront toujours pas synchronisées). volatile ne peut pas non plus être appliqué à une variable locale.

Ainsi, lorsque vous traitez avec plusieurs threads, vous devez toujours utiliser une technique de synchronisation des threads sur des ressources précieuses.

Pour plus d'informations - lisez this réponse, qui a une explication plus approfondie des différentes techniques. (exemple, il y a environ int, mais cela n'a pas vraiment d'importance, il décrit l'approche générale.)

25
Yura

Un peu en retard mais devrait être utile aux autres.

Vous pouvez implémenter votre propre booléen thread-safe de la manière suivante:

// default is false, set 1 for true.
private int _threadSafeBoolBackValue = 0;

public bool ThreadSafeBool
{
    get { return (Interlocked.CompareExchange(ref _threadSafeBoolBackValue, 1, 1) == 1); }
    set
    {
        if (value) Interlocked.CompareExchange(ref _threadSafeBoolBackValue, 1, 0);
        else Interlocked.CompareExchange(ref _threadSafeBoolBackValue, 0, 1);
    }
}

Assurez-vous d'utiliser la propriété partout, n'accédez jamais directement à la variable int.

16
lilo0