2016-08-02 10 views
0

Ich entwickle ein Programm, mit dem Sie mehrere XML-Dateien auswählen und an einen Webserver senden können.Multi Threading, Thread läuft, ohne auf andere Threads zu warten

Jede gesendete XML-Datei würde in einem Thread ausgeführt werden, sodass der Datenversand parallel ausgeführt wird. Das Problem, das ich habe, ist, dass wenn ich die erste Datei gebe, es früh antwortet, ohne sogar die nächsten paar Dateien einzugeben.

Ich weiß nicht, wie alle Threads warten, bis ich tippe, um zu beginnen, alle auf einmal auf einzelnen threads zu senden. Ich versuchte eine Implementierung unten, aber es reagiert zu früh, nachdem ich die erste Datei eingegeben habe.

Heres mein Code:

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Net; 
using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Xml; 

namespace XMLSender 
{ 
    class Program 
    { 
     private static string serverUrl; 

     static void Main(string[] args) 
     { 
      Console.WriteLine("Please enter the URL to send the XML File"); 
      serverUrl = Console.ReadLine(); 
      List<Thread> threads = new List<Thread>(); 

      string fileName = ""; 
      do 
      { 
       Console.WriteLine("Please enter the XML File you Wish to send"); 
       fileName = Console.ReadLine(); 
       Thread t = new Thread(new ParameterizedThreadStart(send));    
       threads.Add(t); 
      } 
      while (fileName != "start"); //Ends if user enters an empty line 
      foreach (Thread t in threads) 
      { 
       t.Start(); 
      } 
      foreach (Thread t in threads) 
      { 
       t.Join(); 
      } 

     } 
     static private void send(object data) 
     { 
      try 
      { 
       //ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 
       HttpWebRequest request = (HttpWebRequest)WebRequest.Create(serverUrl); 
       byte[] bytes; 

       //Load XML data from document 
       XmlDocument doc = new XmlDocument(); 
       doc.Load((string)data); 
       string xmlcontents = doc.InnerXml; 

       //Send XML data to Webserver 
       bytes = Encoding.ASCII.GetBytes(xmlcontents); 
       request.ContentType = "text/xml; encoding='utf-8'"; 
       request.ContentLength = bytes.Length; 
       request.Method = "POST"; 
       Stream requestStream = request.GetRequestStream(); 
       requestStream.Write(bytes, 0, bytes.Length); 
       requestStream.Close(); 

       // Get response from Webserver 
       HttpWebResponse response; 
       response = (HttpWebResponse)request.GetResponse(); 
       Stream responseStream = response.GetResponseStream(); 
       string responseStr = new StreamReader(responseStream).ReadToEnd(); 
       Console.Write(responseStr + Environment.NewLine); 

      } 
      catch (Exception e) 
      { 
       Console.WriteLine("An Error Occured" + Environment.NewLine + e); 
       Console.ReadLine(); 
      } 
     } 
    } 
} 
+2

Verwenden Sie den Task und nicht Thema: http://stackoverflow.com/questions/13429129/task-vs-thread-differences Beispiel: http://stackoverflow.com/a/26588973/47351 – RvdK

+0

Was meinst du mit "es antwortet"? Du benutzt diesen Satz zweimal, aber ich verstehe nicht, was "es" ist und wie diese Antwort lauten würde. –

+0

Die Antwort kommt vom Server zu schnell, da es in der Hauptsache der Antwortteil ist. unter dem // Get Response-Teil – Freon

Antwort

2

Wenn Sie auf einmal alle Themen starten wollen, in Ihrem do-while-Schleife, nicht noch die Fäden beginnen. (Dont rufen t.Start())

Stattdessen in der Zwischenzeit die Dateinamen in einer Liste speichern und dann, nach der while-Schleife, legen Sie eine weitere foreach-Schleife, die dann alle Fäden beginnt:

string fileName = ""; 
List<string> names = new List<string>(); 
do 
{ 
    Console.WriteLine("Please enter the XML File you Wish to send"); 
    fileName = Console.ReadLine(); 
    if(fileName != "start") 
    { 
     Thread t = new Thread(new ParameterizedThreadStart(send));    
     threads.Add(t); 
     names.Add(fileName); 
    } 
} 
while (fileName != "start"); 

foreach (Thread t in threads) 
{ 
    t.Start(names[0]); 
    names.RemoveAt(0); 
} 

Bearbeiten: Ich habe eine Überprüfung hinzugefügt, um sicherzustellen, dass Sie keinen weiteren Thread hinzufügen, wenn Sie start eingeben, da die Schleife immer noch beendet wird, auch wenn die Bedingung der Schleife nicht mehr wahr ist.
Ohne den Haken würde ein neuer Thread hinzugefügt werden das Ende mit start als Parameter hinzufügen.

+0

In Ordnung, also habe ich es getan, (aktualisierter Code) und ich bekomme diese Ausnahme Ein Fehler aufgetreten System.ArgumentNullException: Wert kann nicht null sein. Parametername: url – Freon

+0

Ihr Recht, das habe ich total vergessen. Ich bearbeite meine Antwort – zockDoc

+0

Aus irgendeinem Grund denkt es, dass Start eine Datei ist, und ich bekomme eine Ausnahme, aber ich bekomme die Antwort für die eigentliche Datei, Going Code zu aktualisieren, um darüber nachzudenken. – Freon

2

Erstellen Sie zuerst eine ManulResetEvent. Dieses Ereignis kann dazu führen, dass Threads warten, bis ein bestimmtes Ereignis eintritt. Die ManulResetEvent wird dann ausgelöst, wenn alle Threads erlaubt sind, fortzufahren. Wie folgt aus:

class Program 
{ 
    private static readonly ManualResetEvent _wait = new ManualResetEvent(false); 
    ... 

In Ihrem Thread-Code, lassen Sie alle Threads warten:

static private void send(object data) 
{ 
    _wait.WaitOne(); 
    ... 

In Ihrem Main-Methode lösen das Ereignis nach alle Dateien eingeben:

... 
while (fileName != ""); //Ends if user enters an empty line 
_wait.Set() 
foreach (Thread t in threads) 
    ... 
+0

das wird nur einen Thread weitergehen lassen – vidstige

+0

@vidstich: Können Sie es ausarbeiten. Da stimme ich dem zu: Der Thread wird fortgesetzt, wenn er gestartet wird und weiterlaufen darf. Meine Annahme des Problems ist, dass der Hauptthread die Eingabe vom Benutzer (mit der Konsole) fragt, während der zweite Thread alle Antworten auf dieselbe Konsole schreibt, was es für den Benutzer schwierig macht. Auf diese Weise starten die Threads (und geben Informationen an die Konsole aus), nachdem der Benutzer die Dateinamen eingegeben hat. –

+0

ah, du hast recht. Ich lese zu schnell und habe den Eindruck, dass dort mehr Threads involviert sind. – vidstige

1

Eine zweite Lösung könnte den Thread initialisieren, ohne sie zu starten, aber mit dem Dateinamen-Parameter:

... 
filename = Console.ReadLine(); 
Thread t = new Thread(() => send(filename)); 
threads.Add(t); 
... 

Und außerhalb der Schleife, starten Sie alle Fäden:

foreach (Thread t in threads) 
{ 
    t.Start(); 
} 
+0

Ah ich bekomme die gleiche Ausnahme von oben: System.ArgumentException: Die URL darf nicht leer sein. Parametername: url bei System.Xml.XmlTextReaderImpl..ctor (String url, XmlNameTable nt) bei System.Xml.XmlDocument.Load (String filename) – Freon

+0

Es kann möglich sein, dass, wenn es das Hauptprogramm im ausführt versuchen Sie/fangen Sie, dass es die URL nicht weiß ABER ich sage es an der Oberseite, um es bereits zu sein. Seltsam ... – Freon

+0

Deshalb müssen Sie den Thread wie in meiner Antwort angegeben den Dateinamen bereitstellen. –