78 Stimmen

Gibt es ein besseres Warteschema für c#?

Ich habe diese Art von Kodierung schon ein paar Mal erlebt.

for (int i = 0; i < 10; i++)
{
   if (Thing.WaitingFor())
   {
      break;
   }
   Thread.Sleep(sleep_time);
}
if(!Thing.WaitingFor())
{
   throw new ItDidntHappenException();
}

Es sieht einfach nach schlechtem Code aus, gibt es einen besseren Weg, dies zu tun / ist es ein Symptom für schlechtes Design?

2voto

Daniel Hilgarth Punkte 165768

Ein Aufruf zur Thread.Sleep ist immer eine aktive Wartezeit, die vermieden werden sollte.
Eine Alternative wäre die Verwendung einer Zeitschaltuhr. Zur einfacheren Verwendung könnten Sie diesen in einer Klasse kapseln.

2voto

Ishpeck Punkte 1983

Ich rate normalerweise davon ab, Ausnahmen zu machen.

// Inside a method...
checks=0;
while(!Thing.WaitingFor() && ++checks<10) {
    Thread.Sleep(sleep_time);
}
return checks<10; //False = We didn't find it, true = we did

2voto

Kornél Regius Punkte 2909

Ich denke, Sie sollten AutoResetEvents verwenden. Sie funktionieren hervorragend, wenn Sie darauf warten, dass ein anderer Thread seine Aufgabe beendet

Beispiel:

AutoResetEvent hasItem;
AutoResetEvent doneWithItem;
int jobitem;

public void ThreadOne()
{
 int i;
 while(true)
  {
  //SomeLongJob
  i++;
  jobitem = i;
  hasItem.Set();
  doneWithItem.WaitOne();
  }
}

public void ThreadTwo()
{
 while(true)
 {
  hasItem.WaitOne();
  ProcessItem(jobitem);
  doneWithItem.Set();

 }
}

2voto

Gebb Punkte 6128

So können Sie es machen mit System.Threading.Tasks :

Task t = Task.Factory.StartNew(
    () =>
    {
        Thread.Sleep(1000);
    });
if (t.Wait(500))
{
    Console.WriteLine("Success.");
}
else
{
    Console.WriteLine("Timeout.");
}

Wenn Sie Tasks jedoch aus irgendeinem Grund nicht verwenden können (z. B. eine Anforderung von .Net 2.0), können Sie ManualResetEvent wie in der Antwort von JaredPar erwähnt, oder verwenden Sie etwas wie dieses:

public class RunHelper
{
    private readonly object _gate = new object();
    private bool _finished;
    public RunHelper(Action action)
    {
        ThreadPool.QueueUserWorkItem(
            s =>
            {
                action();
                lock (_gate)
                {
                    _finished = true;
                    Monitor.Pulse(_gate);
                }
            });
    }

    public bool Wait(int milliseconds)
    {
        lock (_gate)
        {
            if (_finished)
            {
                return true;
            }

            return Monitor.Wait(_gate, milliseconds);
        }
    }
}

Mit dem Wait/Pulse-Ansatz erstellen Sie nicht explizit Ereignisse, so dass Sie sich nicht um deren Beseitigung kümmern müssen.

Beispiel für die Verwendung:

var rh = new RunHelper(
    () =>
    {
        Thread.Sleep(1000);
    });
if (rh.Wait(500))
{
    Console.WriteLine("Success.");
}
else
{
    Console.WriteLine("Timeout.");
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X