Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Applikation mit Warteschlange [SyncQueue<T>-Klasse]
JuriG
myCSharp.de - Member



Dabei seit:
Beiträge: 33

Themenstarter:

Applikation mit Warteschlange [SyncQueue<T>-Klasse]

beantworten | zitieren | melden

Hallo!

ich habe eine (vermutlich) sehr einfache Frage,

ich möchte in meiner c# Konsolenanwendung (die als Dienst läuft), eine Art Warteschlange integrieren,

d.h. Wenn ein Arbeitspaket reinkommt, wird er abgearbeitet, kommt noch ein Arbeitspaket währenddessen rein, wird er in die Warteschlange gepackt und erst später abgearbeitet.

Wie kann ich das am Besten erreichen?

Für die Hilfe wäre ich sehr dankbar!
private Nachricht | Beiträge des Benutzers
tscherno
myCSharp.de - Member

Avatar #avatar-2584.gif


Dabei seit:
Beiträge: 637
Herkunft: Nürnberger Land

beantworten | zitieren | melden

Hallo,

sieh dir mal die Klasse System.Collections.Generic.Queue an.

Gruss
tscherno
To understand recursion you must first understand recursion
-
http://www.ilja-neumann.com
C# Gruppe bei last.fm
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo tscherno,

wobei die Queue<>-Klasse nicht synchronisiert ist. Und typischerweise werden de Aufträge von unterschiedlichen Threads eingestellt und ausgelesen. Ich habe neulich mal eine minimale, synchronisierte Queue (inkl. kleinem Testprogramm) geschrieben:


using System;
using System.Collections.Generic;
using System.Threading;
using System.Diagnostics;

//*****************************************************************************
public class SyncQueue <T>
{
   //--------------------------------------------------------------------------
   private Queue <T> _q   = new Queue <T> ();

   //==========================================================================
   // <summary>Trägt einen Eintrag (ohne zu warten) ein</summary>
   public void Enqueue (T tItem)
   {
      lock (this) {
         _q.Enqueue (tItem);
         Monitor.Pulse (this);
         Debug.WriteLine (Thread.CurrentThread.Name + " Enqueue ==> " + _q.Count);
      }
   }

   //==========================================================================
   // <summary>
   //    Holt einen Eintrag aus der Queue heraus und wartet dabei nötigenfalls
   //    solange bis wieder ein Eintrag vorhanden ist.
   // </summary>
   public T Dequeue ()
   {
      lock (this) {
         while (_q.Count == 0) {
            Debug.WriteLine (Thread.CurrentThread.Name + " Wait");
            Monitor.Wait (this);
         }
         Debug.WriteLine (Thread.CurrentThread.Name + " Dequeue ==> " + (_q.Count - 1));
         return _q.Dequeue ();
      }
   }
}

//*****************************************************************************
static class App
{
   //-------------------------------------------------------------------------
   private static SyncQueue <int> _sq   = new SyncQueue <int> ();
   private static Random          _rand = new Random ();

   //==========================================================================
   public static void Main (string [] astrArg)
   {
      Debug.Listeners.Clear ();
      Debug.Listeners.Add (new ConsoleTraceListener ());

      for (int i = 0; i < 4; ++i) {
         Thread t = new Thread (RunDequeue);
         t.Name = "D" + i;
         t.Start ();
      }

      for (int i = 0; i < 4; ++i) {
         Thread t = new Thread (RunEnqueue);
         t.Name = "E" + i;
         t.Start ();
      }

   }

   //==========================================================================
   private static void RunEnqueue ()
   {
      for (int i = 1 ; i ≤ 25; ++i) {
         _sq.Enqueue (100);
         Thread.Sleep (_rand.Next (1000));
      }
   }

   //==========================================================================
   private static void RunDequeue ()
   {
      for (int i = 1 ; i ≤ 25; ++i) {
         _sq.Dequeue ();
         Thread.Sleep (_rand.Next (995));
      }
   }
}

herbivore

PS: Der Code ist jetzt auch unter SyncQueue <T> - Eine praktische Job-Queue verfügbar. Dort findet sich auch eine weitergehende Beschreibung der Klasse.

Suchhilfe: 1000 Worte
private Nachricht | Beiträge des Benutzers
kleines_eichhoernchen
myCSharp.de - Member

Avatar #avatar-2079.jpg


Dabei seit:
Beiträge: 4055
Herkunft: Ursprünglich Vogtland, jetzt Much

beantworten | zitieren | melden

Hallo Herbivore,
gibt es einen speziellen Grund, warum du einmal lock(this) verwendest und einmal Monitor.Enter(this).

Die Queue hat allerdings noch einen weiteren großen Nachteil, Sicherheitskontext (MSND: SecurityContext Class). Wenn beispielsweise ein Plugin einen Request hinzufügt, das Plugin aber selber nur einen geringen Sicherheitskontext hat, wird es mit dem der Warteschlange ausgeführt (bzw. mit dem Thread, der die Sachen herausholt und verarbeitet). Richtig wäre es den Sicherheitskontext beim hinzufügen festzuhalten und beim Ausführen des Requests dem Thread diesen Sicherheitskontext zu verpassen.
Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo kleines_eichhoernchen,
Zitat
gibt es einen speziellen Grund, warum du einmal lock(this) verwendest und einmal Monitor.Enter(this).
nein, deshalb verwende ich jetzt auch an beiden Stellen lock(this). Danke für den Hinweis.

Was den Sicherheitskontext angeht, kann das in dem von dir beschriebenen Fall natürlich eine Rolle spielen. Es gibt aber sicher mehr Fälle, in denen man das nicht berücksichtigen muss. Du kannst gerne eine Erweiterung schreiben, die den Sicherheitskontext berücksichtigt.

herbivore
private Nachricht | Beiträge des Benutzers
chavez
myCSharp.de - Member



Dabei seit:
Beiträge: 257
Herkunft: Österreich

beantworten | zitieren | melden

Aber erhält man nicht bereits mittels Queue.Synchronized() eine synchronisierte Queue. Wozu also eine selbst basteln?
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo chavez,

grundsätzlich hast du recht. Man sollte das Rad nicht neu erfinden. Jedoch liefert Queue.Synchronized eine untypisierte Collection, wogegen meine Queue generisch und damit typsicher ist. Der entscheidende Unterschied ist aber, dass Queue.Dequeue eine Exception wirft, wenn die Queue leer ist, statt wie meine Queue zu warten, bis ein Element mit Enqueue hinzugefügt wurde. Also genau das, was man für eine Job-Queue braucht.

herbivore
private Nachricht | Beiträge des Benutzers