WSACancelBlockingCall bei Multithreading Versuch

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von shad.

    WSACancelBlockingCall bei Multithreading Versuch

    Guten Tag,

    ich versuche meinen Fehler so gut wie möglich zu beschreiben, jedoch kann ich nicht versichern, dass ich es direkt beim ersten mal hin bekomme: Ich habe eine Anwendung, welche für mich viele Informationen von einer Webseite überprüfen soll und das über 50 laufende Threads (die Informationen müssen sehr schnell verarbeitet werden). Die Webseite gehört mir und ist extra für diesen Verwendungszweck programmiert worden.

    Das Problem ist nun, dass ich sehr viele Fehler erhalte, welche wie folgt aussehen:


    Eigentlich würde ich diese Fehler einfach ignorieren, jedoch wird bei jedem Fehler eine Anfrage, die ich benötige, übersprungen. Ich habe mir bereits mehrere Lösungen im Internet angeschaut, jedoch scheint keine zu funktionieren.

    Gehen wir mal zum Verlauf meines Programmes: Ich habe einen Button, welcher einen BackgroundWorker startet. Dieser BGW beinhaltet folgenden Code:

    C#-Quellcode

    1. int threadcount = 50; //Wenn ich die Threads auf 1 beschränke, funktioniert alles wunderbar!
    2. ThreadPool.SetMinThreads(threadcount, threadcount);
    3. ThreadPool.SetMaxThreads(threadcount, threadcount);
    4. ServicePointManager.DefaultConnectionLimit = threadcount;
    5. ServicePointManager.Expect100Continue = false;
    6. try
    7. {
    8. List<string>.Enumerator enumerator = informations.GetEnumerator();
    9. while (enumerator.MoveNext())
    10. {
    11. string current = enumerator.Current;
    12. ThreadPool.QueueUserWorkItem(information =>
    13. {
    14. CheckInformation(informations.ToString());
    15. }, current);
    16. }
    17. }
    18. finally
    19. {
    20. List<string>.Enumerator enumerator = new List<string>.Enumerator();
    21. enumerator.Dispose();
    22. }


    Laut dem Internet, scheint die Dispose Funktion das Problem zu sein, weil ein Thread bei 50 erlaubten Connections dennoch versucht, einen 51. Thread zu starten (wenn ich das richtig verstanden habe).

    Jedoch zeigt mit die Fehlermeldung an, dass mein Fehler in Zeile 101 liegt, welche folgenden Code beinhaltet:

    C#-Quellcode

    1. Source2 = streamReader2.ReadToEnd(); // Liegt in CheckInformation()


    Den kompletten Code kann ich leider nicht zur Verfügung stellen, ich habe dafür nicht die ausreichende Berechtigung erhalten. Ich hoffe jedoch, dass es reicht und falls nicht, versuche ich einen akkuraten Pseudocode zu posten, wozu ich grade leider keine Zeit habe.

    Ich mag diese Methode an Threads übrigens überhaupt nicht. Jemand eine Idee, wie ich 50 Threads gleichzeitig laufen lassen kann? Simpler?
    Wenn ich eine Frage stelle, habe ich sie bereits gegooglet. Ja, es kommt vor, dass ich die Antwort übersehe. Ja, es kommt vor, dass ich sie nicht verstehe. Deshalb bin ich hier. Wenn dies eure Frage war, dann antwortet bitte nicht. Es stiehlt sämtliche Motivation.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Sekki“ ()

    Hi, ich müsste mich jetzt weit aus dem Fenster lehnen, da ich ja den rest des Codes nicht kenne, aber eine schneller recherge hat ergeben, das es meist daran zu liegen scheint, das einer der Threads einen Socket schließen will / schließt, so dass weitere Threads dann nicht mehr drauf zugreifen können.

    z.B. Link oder anderer Link

    ich Hoffe das hilft dir evtl. ein wenig.

    LG
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If

    asusdk schrieb:

    das einer der Threads einen Socket schließen will / schließt


    Das habe ich mir auch gedacht (der Meldung zu entnehmen), aber ich habe es nicht hinbekommen, es in meinem Code zu fixxen. Hast du eventuell mit dem gegeben Code von mir bereits eine Möglichkeit? Meines Wissens habe ich alles richtig Disposed..
    Wenn ich eine Frage stelle, habe ich sie bereits gegooglet. Ja, es kommt vor, dass ich die Antwort übersehe. Ja, es kommt vor, dass ich sie nicht verstehe. Deshalb bin ich hier. Wenn dies eure Frage war, dann antwortet bitte nicht. Es stiehlt sämtliche Motivation.
    Ich denke, dass wir auf jeden Fall mehr Code brauchen, da der Kontext für das Problem fehlt. Wir können mit dem Code oben nicht sehen, wie und wo Requests gemacht werden, oder wie es zu der SocketException kommen kann. Anhand der Exception-Message kann man zwar raten, aber am besten wäre ein Beispielcode, bei dem man das Problem lokal nachstellen kann.
    Alternativ wäre es gut, die Codestellen zu haben, bei denen die Sockets (oder die WebRequests) erstellt und benutzt werden. Desweiteren bräuchten wir sehr wahrscheinlich die Methode, in der die Exception auftritt, also CheckException (vermutlich?).


    Noch ein paar kleine Infos am Rande, bitte ignorieren, wenn der Code oben durch Vereinfachung/Kürzung zustande kam. Ich will nur ausschließen, dass dadurch Fehler auftreten.

    In diesem Teil rufst du ToString() auf informations auf, also auf die Liste und nicht auf den Parameter des Callbacks auf. Das ist wahrscheinlich nicht beabsichtigt.

    C#-Quellcode

    1. ThreadPool.QueueUserWorkItem(information =>
    2. {
    3. CheckInformation(informations.ToString());
    4. }, current);


    Es macht keinen Sinn, Dispose() auf einen List<T> Enumerator aufzurufen, weil es keinen Effekt hat, siehe hier den Code dazu: referencesource.microsoft.com/…ions/generic/list.cs,1154
    Abgesehen davon macht der Teil hier keinen Sinn, weil nicht der Enumerator von oben disposed wird. Stattdessen wird einfach ein neuer erstellt und sofort wieder disposed.

    C#-Quellcode

    1. List<string>.Enumerator enumerator = new List<string>.Enumerator();
    2. enumerator.Dispose();


    Generell kann der Code einfach zu hierzu verkürzt werden:

    C#-Quellcode

    1. int threadcount = 50;
    2. ThreadPool.SetMinThreads(threadcount, threadcount);
    3. ThreadPool.SetMaxThreads(threadcount, threadcount);
    4. ServicePointManager.DefaultConnectionLimit = threadcount;
    5. ServicePointManager.Expect100Continue = false;
    6. foreach (var info in informations)
    7. {
    8. ThreadPool.QueueUserWorkItem(info => CheckInformation(info.ToString()), info);
    9. }


    Viele Grüße!
    @shad
    Ich habe es nun umgeschrieben, danke für die kleine Version des Codes. War noch experimentell. Ich habe nun versucht einen Pseudo Code zu erstellen, doch ich versage drinnen. Die Webseite, welche ich nutze, wurde extra für den Fall programmiert und hat Datenbank Zugriff. Die Webseite ist nicht gesichert, daher ist es zu riskant, hier etwas davon zu veröffentlichen.

    Hast du vielleicht ein gutes Beispiel, wie man sonst noch Multithreaden könnte? Bei 100 Threads rastet das Programm aus und macht komische Dinge, obwohl mein PC sehr gut ist. Ich habe auch noch nie Multithreading in der Art gesehen, wie ich es programmiert habe. Du würdest mir damit sehr helfen und danke für die ausführliche Antwort, hat mich sehr gefreut.

    Die Dispose Funktion habe ich entfernt, da war ein Logikfehler enthalten. Danke für die Information.

    Edit: Habs mal doch gemacht. Habe mal die sensiblen Stellen zensiert.
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Data;
    5. using System.Drawing;
    6. using System.Linq;
    7. using System.Text;
    8. using System.Threading.Tasks;
    9. using System.Windows.Forms;
    10. using System.IO;
    11. using System.Net;
    12. using System.Text.RegularExpressions;
    13. using System.Threading;
    14. namespace F_ACCESS_CHECKER
    15. {
    16. public partial class Form1 : Form
    17. {
    18. HttpWebResponse HTTPWRes;
    19. UTF8Encoding UTF8;
    20. string Headers;
    21. string Source;
    22. string Source2;
    23. string tempCrap;
    24. List<string> informations;
    25. public Form1()
    26. {
    27. informations = new List<string>();
    28. Control.CheckForIllegalCrossThreadCalls = false;
    29. UTF8 = new UTF8Encoding();
    30. InitializeComponent();
    31. }
    32. private void CheckInformations(string information)
    33. {
    34. try
    35. {
    36. string user = information;
    37. WebRequest webRequest = WebRequest.Create("ZENSIERT");
    38. webRequest.Method = "GET";
    39. HTTPWRes = (HttpWebResponse)webRequest.GetResponse();
    40. if (HTTPWRes.StatusCode == HttpStatusCode.OK)
    41. {
    42. HTTPWRes.Close();
    43. Headers = HTTPWRes.Headers.ToString();
    44. Match match = Regex.Match(Headers, "Set-Cookie: (.*?);Version=1");
    45. byte[] Bytes = UTF8.GetBytes(String.Concat(new String[] { "ZENSIERT" }));
    46. HttpWebRequest HTTPWReq = (HttpWebRequest)WebRequest.Create("ZENSIERT");
    47. HTTPWReq.Method = "GET";
    48. HTTPWReq.ContentType = "application/x-www-form-urlencoded";
    49. HTTPWReq.Referer = "ZENSIERT";
    50. HTTPWReq.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0";
    51. HTTPWReq.ContentLength = (long)Bytes.Length;
    52. HTTPWReq.Headers.Add("ZENSIERT");
    53. HTTPWReq.Headers.Add("ZENSIERT");
    54. Stream reqStream = HTTPWReq.GetRequestStream();
    55. reqStream.Write(Bytes, 0, Bytes.Length);
    56. reqStream.Close();
    57. HTTPWRes = (HttpWebResponse)HTTPWReq.GetResponse();
    58. using (var ReadFile = new StreamReader(HTTPWRes.GetResponseStream(), Encoding.Default))
    59. {
    60. Source = ReadFile.ReadToEnd();
    61. }
    62. HTTPWRes.Close();
    63. string input = HTTPWRes.Headers.ToString();
    64. Match match2 = Regex.Match(input, "HttpOnly,(.*?);Version=1");
    65. if (Source.Contains("Is valid;"))
    66. {
    67. HTTPWReq = (HttpWebRequest)WebRequest.Create("ZENSIERT");
    68. HTTPWReq.Method = "POST";
    69. HTTPWReq.ContentType = "application/x-www-form-urlencoded";
    70. HTTPWReq.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0";
    71. HTTPWReq.Headers.Add("ZENSIERT");
    72. Stream reqStream2 = HTTPWReq.GetRequestStream();
    73. reqStream2.Close();
    74. HTTPWRes = (HttpWebResponse)HTTPWReq.GetResponse();
    75. using (var ReadFile = new StreamReader(HTTPWRes.GetResponseStream(), Encoding.Default))
    76. {
    77. Source2 = ReadFile.ReadToEnd();
    78. }
    79. HTTPWRes.Close();
    80. if (Source2.Contains(">Valid by Administrator: True<"))
    81. {
    82. MessageBox.Show(information + " has Access!");
    83. }
    84. }
    85. }
    86. }
    87. catch (Exception ex)
    88. {
    89. //
    90. }
    91. }
    92. private void Button1_Click(object sender, EventArgs e)
    93. {
    94. //Begin
    95. backgroundWorker1.WorkerSupportsCancellation = true;
    96. backgroundWorker1.RunWorkerAsync();
    97. }
    98. private void Button2_Click(object sender, EventArgs e)
    99. {
    100. backgroundWorker1.CancelAsync();
    101. }
    102. private void Button3_Click(object sender, EventArgs e)
    103. {
    104. try
    105. {
    106. informations.Clear();
    107. OpenFileDialog dialog = new OpenFileDialog();
    108. dialog.RestoreDirectory = true;
    109. dialog.Multiselect = false;
    110. dialog.Filter = "txt files (*.txt)|*.txt";
    111. dialog.FilterIndex = 1;
    112. dialog.ShowDialog();
    113. if (dialog.FileName != "")
    114. {
    115. List<string> list = new List<string>();
    116. using (StreamReader reader = new StreamReader(dialog.FileName))
    117. {
    118. while (reader.Peek() != -1)
    119. {
    120. list.Add(reader.ReadLine());
    121. }
    122. }
    123. foreach (string str in list)
    124. {
    125. try
    126. {
    127. informations.Add(str);
    128. }
    129. catch (Exception)
    130. {
    131. }
    132. button3.Text = "Check Informations: " + informations.Count().ToString();
    133. }
    134. }
    135. }
    136. catch (Exception)
    137. {
    138. }
    139. }
    140. private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    141. {
    142. int threadcount = (int)numericUpDown1.Value;
    143. ThreadPool.SetMinThreads(threadcount, threadcount);
    144. ThreadPool.SetMaxThreads(threadcount, threadcount);
    145. ServicePointManager.DefaultConnectionLimit = threadcount;
    146. ServicePointManager.Expect100Continue = false;
    147. try
    148. {
    149. foreach (var info in informations)
    150. {
    151. ThreadPool.QueueUserWorkItem(p => CheckInformations(info.ToString()), info);
    152. }
    153. }
    154. catch
    155. {
    156. //
    157. }
    158. }
    159. }
    160. }
    Wenn ich eine Frage stelle, habe ich sie bereits gegooglet. Ja, es kommt vor, dass ich die Antwort übersehe. Ja, es kommt vor, dass ich sie nicht verstehe. Deshalb bin ich hier. Wenn dies eure Frage war, dann antwortet bitte nicht. Es stiehlt sämtliche Motivation.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Sekki“ ()

    Forum, enttäusch mich nicht! Du hast mir bereits hunderte male geholfen, dass kannst du auch!
    Ich hoffe, dass wirklich jemand helfen kann. :/
    Wenn ich eine Frage stelle, habe ich sie bereits gegooglet. Ja, es kommt vor, dass ich die Antwort übersehe. Ja, es kommt vor, dass ich sie nicht verstehe. Deshalb bin ich hier. Wenn dies eure Frage war, dann antwortet bitte nicht. Es stiehlt sämtliche Motivation.
    Hey @Sekki, hast du nicht neulich geschrieben, dass du es zum Laufen bekommen hast? Deswegen habe ich nicht mehr geantwortet.
    Ich kann mir anhand deines Codes leider nicht erklären, wie die Exception auftritt. Allerdings kann ich den Fehler auch nicht reproduzieren.

    Allerdings behaupte ich, dass es bessere Möglichkeiten gibt, dein Problem zu lösen, als über den Threadpool zu gehen. Dafür muss ich aber dein Problem genau verstehen.
    Zum Beispiel verstehe ich nicht, wieso du überhaupt genau 50 Threads brauchst. Ich verstehe deinen Code so, dass du im Endeffekt für jede "Info" in einer Textbox ein paar Requests an die Seite stellen möchtest. Darf ich davon ausgehen, dass du hier Multithreading willst, um die Requests parallel zu starten und somit die gesamte Zeit zu verkürzen?

    Wenn das der Fall ist, könnte man allerdings auch anders an die Sache rangehen. Bist du auf .NET >= 4.5 oder .NET Core, also hast du Zugriff auf Tasks und async/await? Damit wäre es am Leichtesten.