27 votes

Est-il sûr d'utiliser un indicateur booléen pour empêcher un thread de s'exécuter en C #

Ma principale préoccupation est le drapeau booléen... est-il sécuritaire d'utiliser sans aucune synchronisation? J'ai lu à plusieurs endroits que c'est atomique (y compris la documentation).

class MyTask
{
    private ManualResetEvent startSignal;
    private CountDownLatch latch;
    private bool running;

    MyTask(CountDownLatch latch)
    {
        running = false;
        this.latch = latch;
        startSignal = new ManualResetEvent(false);
    }

    // A method which runs in a thread
    public void Run()
    {
        startSignal.WaitOne();
        while(running)
        {
            startSignal.WaitOne();
            //... some code
        }
        latch.Signal();
    }

    public void Stop()
    {
        running = false;
        startSignal.Set();
    }

    public void Start()
    {
        running = true;
        startSignal.Set();
    }

    public void Pause()
    {
        startSignal.Reset();
    }

    public void Resume()
    {
        startSignal.Set();
    }
}

Est-ce un moyen sûr pour la conception d'une tâche de cette façon? Des suggestions, des améliorations, des commentaires?

Note: j'ai écrit mon personnalisée CountDownLatch de la classe dans le cas où vous vous demandez où je veux en venir à partir de.

Mise à jour:
Voici mon CountDownLatch trop:

public class CountDownLatch 
{
    private volatile int m_remain;
    private EventWaitHandle m_event;

    public CountDownLatch (int count)
    {
        if (count < 0)
            throw new ArgumentOutOfRangeException();
        m_remain = count;
        m_event = new ManualResetEvent(false);
        if (m_remain == 0)
        {
            m_event.Set();
        }
    }

    public void Signal()
    {
        // The last thread to signal also sets the event.
        if (Interlocked.Decrement(ref m_remain) == 0)
            m_event.Set();
    }

    public void Wait()
    {
        m_event.WaitOne();
    }
}

36voto

Remus Rusanu Points 159382

Vous meilleure marque c' volatile bien que:

Le mot clé volatile indique qu'un le champ peut être modifié par de multiples simultanément à l'exécution de threads. Champs qui sont déclarées volatiles ne sont pas sous réserve que les optimisations du compilateur supposons accès par un seul thread. Cette s'assure que les plus up-to-date de valeur est présent sur le terrain en tout temps.

Mais je voudrais changer votre boucle:

    startSignal.WaitOne();
    while(running)
    {
        //... some code
        startSignal.WaitOne();
    }

Comme il est dans votre post le 'code' peut exécuter lorsque le thread est arrêté (ie. lorsque l'Arrêt est appelé) qui est inattendu et peut-être même erronée.

3voto

Kevin Sylvestre Points 15551

3voto

Michael Burr Points 181287

Les booléens sont atomiques en C #, cependant, si vous voulez le modifier dans un thread et le lire dans un autre, vous devrez au moins le marquer comme volatile. Sinon, le thread de lecture ne peut le lire qu'une seule fois dans un registre.

0voto

akapet Points 31

BTW, je viens de remarquer cette partie du code:

 // A method which runs in a thread
    public void Run()
    {
        startSignal.WaitOne();
        while(running)
        {
            startSignal.WaitOne();
            //... some code
        }
        latch.Signal();
    }
 

Vous devrez débloquer le thread de travail deux fois à l'aide de "startSignal.Set ()" pour que le code dans le bloc while s'exécute.

Est-ce délibéré?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X