2009-05-30 5 views
0



Ich habe eine Methode, die ich gerne wieder und wieder laufen würde. Ich möchte in der Lage sein, diesen Prozess zu starten und zu stoppen.C# Methode Schleife und Kontrolle

Ich habe dieses Muster für einige Sockel Arbeit verwendet und ich frage mich, welche Verbesserungen ich machen kann?

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

Entschuldigen Sie! Fehler behoben abelenky - ich bin müde - jetzt stabil mit einigen von Orion vorgeschlagenen Funktionen – divinci

Antwort

1

Eine sicherere Version wäre es, wie dies zu tun:

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 für die feineren Punkte auf volatile Siehe vs Verriegelungs

+0

@Orion - Ich mag, dass Sie das Problem aufgeworfen haben, was passiert, wenn die Aktion auf Null gesetzt ist - wenn Sie delagate() eine Null, was passiert? – divinci

+0

Eine NullReferenceException passiert :-) –

1

Nun, Sie sollten die DoMethodToLoop als flüchtig ausdrücken. Wie in der MSDN angegeben:

"Das flüchtige Schlüsselwort zeigt an, dass ein Feld im Programm von etwas wie dem Betriebssystem, der Hardware oder einem gleichzeitig ausführenden Thread geändert werden kann."

Ich bin in Eile, aber Sie sollten this tutorial aus dem Code einschalten.

+0

@Cris - guter Punkt - ill edit. – divinci

+0

Ja - nicht volatil zu sein ist etwas, das Sie beißen würde, wenn Sie zu einer CPU-Architektur wie Itanium wechseln würden. – RichardOD