Frage

ich eine Anwendung, die viele Fälle hat. Jeder Fall hat viele mehrseitige tif-Dateien. Ich brauche die tf-Dateien in PDF-Datei verdeckte. Da es so viele Dateien sind, dachte ich, dass ich den Umwandlungsprozess einfädeln konnte. Ich Begrenzung derzeit den Prozess zu zehn Conversions zu einem Zeitpunkt (das heißt zehn Stufen). Wenn eine Konvertierung abgeschlossen ist, sollte eine andere starten.

Dies ist das aktuelle Setup verwende ich.

private void ConvertFiles()
{
  List<AutoResetEvent> semaphores = new List<AutoResetEvet>();
  foreach(String fileName in filesToConvert)
  {
    String file = fileName;

    if(semaphores.Count >= 10)
    {
      WaitHandle.WaitAny(semaphores.ToArray());
    }


    AutoResetEvent semaphore = new AutoResetEvent(false);
    semaphores.Add(semaphore);

    ThreadPool.QueueUserWorkItem(
      delegate
      { 
        Convert(file);
        semaphore.Set();
        semaphores.Remove(semaphore);
      }, null);
  }

  if(semaphores.Count > 0)
  {
    WaitHandle.WaitAll(semaphores.ToArray());
  }
}

diese verwenden, führt manchmal zu einer Ausnahme unter Angabe der WaitHandle.WaitAll () oder WaitHandle.WaitAny () Array-Parameter darf nicht länger als eine Länge von 65. Was ich falsch in diesem Ansatz tue und wie kann ich es beheben?

War es hilfreich?

Lösung

Es gibt ein paar Probleme mit dem, was Sie geschrieben haben.

1., ist es nicht Thread-sicher. Sie haben mehrere Threads das Hinzufügen, Entfernen und warten auf das Array von AutoResetEvents. Die einzelnen Elemente der Liste kann auf separate Threads zugegriffen werden, aber alles, was entfernt oder überprüft alle Elemente (wie die WaitAny Anruf), Notwendigkeit zu tun, so innerhalb eines Schlosses hinzufügt.

2., gibt es keine Garantie, dass der Code nur 10 Dateien auf einmal verarbeiten. Der Code zwischen, wenn die Größe der Liste wird überprüft, und der Punkt, an dem ein neues Element hinzugefügt wird, ist offen für mehrere Threads durchzukommen.

3., gibt es Potenzial für die Themen in der QueueUserWorkItem die gleiche Datei zu konvertieren. Ohne die Dateinamen innerhalb der Schleife aufnehmen, den Thread, konvertiert die Datei, was Wert ist in Dateinamen verwenden, wenn es ausgeführt wird, nicht, was war in filename, wenn Sie QueueUserWorkItem genannt.

Diese Codeproject Artikel sollten Sie in die richtige Richtung für das, was Sie zu tun versuchen: http://www.codeproject.com/KB/threads/SchedulingEngine.aspx

EDIT:

var semaphores = new List<AutoResetEvent>();
        foreach (String fileName in filesToConvert)
        {
            String file = fileName;
            AutoResetEvent[] array;
            lock (semaphores)
            {
                array = semaphores.ToArray();
            }
            if (array.Count() >= 10)
            {
                WaitHandle.WaitAny(array);
            }

            var semaphore = new AutoResetEvent(false);
            lock (semaphores)
            {
                semaphores.Add(semaphore);
            }
            ThreadPool.QueueUserWorkItem(
              delegate
              {
                  Convert(file);
                  lock (semaphores)
                  {
                      semaphores.Remove(semaphore);
                  }
                  semaphore.Set();
              }, null);
        }

Ich persönlich glaube nicht, dass ich es auf diese Weise tun würde ... aber mit dem Code arbeiten Sie haben, sollte diese Arbeit.

Andere Tipps

Sind Sie ein echter Semaphore mit ( System.Threading )? Wenn Semaphore verwenden, weisen Sie in der Regel Ihre max Ressourcen und es wird automatisch für Sie blockieren (wie Sie hinzufügen & Release). Sie können mit dem WaitAny Ansatz gehen, aber ich bin immer das Gefühl, dass Sie den schwierigeren Weg gewählt haben.

Sieht aus wie Sie benötigen den Griff zu entfernen, die die WaitAny Funktion ausgelöst

, um fortzufahren
if(semaphores.Count >= 10)
{
  int index = WaitHandle.WaitAny(semaphores.ToArray());
  semaphores.RemoveAt(index);
}

Also im Grunde möchte ich entfernen:

semaphores.Remove(semaphore);

Anruf aus dem Thread und verwenden Sie die oben, die signalisierte Ereignis zu entfernen und sehen, ob das funktioniert.

Vielleicht sollten Sie nicht so viele Ereignisse erstellen?

// input
var filesToConvert = new List<string>();
Action<string> Convert = Console.WriteLine;

// limit
const int MaxThreadsCount = 10;

var fileConverted = new AutoResetEvent(false);
long threadsCount = 0;

// start
foreach (var file in filesToConvert) {
    if (threadsCount++ > MaxThreadsCount) // reached max threads count 
        fileConverted.WaitOne();          // wait for one of started threads

    Interlocked.Increment(ref threadsCount);

    ThreadPool.QueueUserWorkItem(
        delegate {
            Convert(file);

            Interlocked.Decrement(ref threadsCount);
            fileConverted.Set();
        });
}

// wait
while (Interlocked.Read(ref threadsCount) > 0) // paranoia?
    fileConverted.WaitOne();
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top