سؤال



لدي طريقة أود أن أركض مرارا وتكرارا. أود أن أكون قادرا على البدء وإيقاف هذه العملية.

لقد كنت أستخدم هذا النمط لبعض أعمال المقبس وأتساءل عن التحسينات التي يمكنني إجراؤها؟

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();
        }
    }
}
هل كانت مفيدة؟

المحلول

سيكون إصدار أكثر أمانا القيام بذلك مثل هذا:

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();
}

يرى هذا السؤال الآخر للحصول على نقاط أدق على قفل VS Virtile

نصائح أخرى

حسنا يجب أن تعبر عن Domethodtoloop كمتقللا. كما هو مذكور في MSDN:

"تشير الكلمة الأساسية المتقلبة إلى أنه يمكن تعديل حقل في البرنامج من خلال شيء مثل نظام التشغيل أو الأجهزة أو مؤشر ترابط تنفيذ".

أنا في عجلة من امرنا ولكن يجب عليك التحقق من هذا البرنامج التعليمي من التبديل على الرمز.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top