Question


J'ai une méthode que je voudrais courir encore et again.I aimeraient être en mesure de démarrer et d'arrêter ce processus.

J'utilise ce modèle pour un travail de prise et je me demande quelles sont les améliorations que je peux faire?

public delegate void VoidMethod();

public class MethodLooper
{
    private VoidMethod methodToLoop;
    private volatile bool doMethod;
    private readonly object locker = new object();
    private readonly Thread loopingThread;

    public void Start()
    {
        if (!doMethod)
        {
            doMethod = true;
            loopingThread.Start();
        }
    }

    public void Stop()
    {
        if (doMethod)
        {
            doMethod = false;
            loopingThread.Join();
        }
    }

    public void ChangeMethod(VoidMethod voidMethod)
    {

        if (voidMethod == null)
            throw new NullReferenceException("voidMethod can't be a null");

        Stop();
        lock (locker)
        {
            methodToLoop = voidMethod;
        }
    }

    public MethodLooper(VoidMethod voidMethod)
    {
        if (voidMethod == null)
            throw new NullReferenceException("voidMethod can't be a null");
        methodToLoop = voidMethod;
        loopingThread = new Thread(new ThreadStart(_MethodLoop));
    }

    private void _MethodLoop()
    {
        VoidMethod methodToLoopCopy;
        while (doMethod)
        {
            lock (methodToLoop)
            {
                methodToLoopCopy = methodToLoop;
            }
            methodToLoopCopy();
        }
    }
}
Était-ce utile?

La solution

Une version plus sûre serait de le faire comme ceci:

private readonly object m_locker = new object(); // readonly so it can never be null
private readonly Thread m_workerThread; // readonly so must set in constructor,
    // and never can be null afterwards

private Action m_methodToRun;
private volatile bool m_keepGoing = true; // needs to be volatile or else you need to lock around accesses to it.

public Constructor()
{
  m_workerThread = new Thread(ThreadWorker);
}

public void SetMethod(Action action)
{
  lock(m_locker)
    m_methodToRun = action;
}

private void ThreadWorker()
{
  while(m_keepGoing)
  {
    // use a lock to take a local copy in case another thread sets m_methodToRun to null
    // while we are processing things
    Action methodLocal;
    lock(m_locker)
      methodLocal = m_methodToRun;

    methodLocal(); // call it
    // Note: Remember that the underlying method being pointed to must ALSO be
    // thread safe. Nothing you do here can make up for that if it is not.
  }
}

private void Stop()
{ 
  m_keepGoing = false; 
  m_workerThread.Join(); // BLOCK and wait for it to finish
}

private void Start()
{ 
  m_keepGoing = true;
  m_workerThread.Start();
}

Voir cette autre question pour les points les plus fins sur volatils vs verrouillage

Autres conseils

Eh bien, vous devez exprimer la doMethodToLoop comme volatile. Comme indiqué dans le MSDN:

  

« Le mot-clé volatile indique qu'un champ peut être modifié dans le programme par quelque chose comme le système d'exploitation, le matériel, ou un fil d'exécuter simultanément. »

Je suis pressé, mais vous devriez consulter cette tutoriel de commutateur sur le code.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top