2009-05-30 2 views
0



У меня есть метод, который я хотел бы запускать снова и снова.Я хотел бы иметь возможность запустить и остановить этот процесс.C# Метод looping и управление

Я использую этот шаблон для работы сокета, и мне интересно, какие улучшения я могу сделать?

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

Извините! ошибка фиксированная abelenky - im усталая - теперь стабильная с некоторыми функциями, предложенными Orion – divinci

ответ

1

Безопаснее версия будет делать это следующим образом:

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

См this other question для тонкостей на летучем против блокировки

+0

@Orion - Мне нравится, что вы подняли вопрос о том, что произойдет, если действие установлено на null - если вы delagate() null, что происходит? – divinci

+0

Ошибка NullReferenceException :-) –

1

Ну, вы должны выразить doMethodToLoop как изменчивый. Как указано в MSDN:

«Ключевое слово volatile указывает, что поле может быть изменено в программе чем-то вроде операционной системы, аппаратного обеспечения или одновременно исполняемого потока».

Я спешу, но вы должны проверить this tutorial с помощью кода.

+0

@Cris - хорошая точка - плохое редактирование. – divinci

+0

Да - не иметь волатильности - это то, что может вас укусить, если вы перейдете на архитектуру процессора, такую ​​как Itanium. – RichardOD

Смежные вопросы