EventWaitHandler - Thread blockieren

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

Es gibt 7 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    EventWaitHandler - Thread blockieren

    Hallo zusammen,

    ich habe ein Problem mit einem EventWaitHandler, mit dem ich einfach nicht weiterkomme. Wie ich bereits in meinem anderen Thread erwähnt habe, sende ich mit einem Client eine Nachricht an einen Server, um von diesen eine Aufgabe abzufragen. Dabei läuft beim Client ein separater Thread zum empfangen der Antwort vom Server. Dieser Empfangsthread löst nun je nach empfangener Nachricht ein bestimmtes Event aus.

    Nun gibt es den Fall, dass einem Ausgelösten Event z.B. eine Aufgabe abgefragt werden muss. Hier wollte ich nun die neuen Methoden einsetzen, damit das direkt ersichtlich wird.

    C#-Quellcode

    1. EventWaitHandle ewh = new EventWaitHandle(false, EventResetMode.AutoReset);


    C#-Quellcode

    1. /// <summary>
    2. /// Ruft die Daten einer speziellen Aufgabe ab
    3. /// </summary>
    4. /// <param name="A_NR">Die ID der Aufgabe</param>
    5. /// <param name="istAktiveAufgabe">Ist die Aufgabe noch aktiv, oder wurde diese bereits erledigt?</param>
    6. /// <returns></returns>
    7. public Aufgabe GetAufgabe(long A_NR, bool istAktiveAufgabe = true)
    8. {
    9. if (!IsLoggedIn)
    10. throw new Exceptions.LoginRequiredException("Aktion erfordert Login am AufgabenServer. Bitte loggen Sie sich ein.");
    11. ServerProtokoll serverProtokoll = new ServerProtokoll()
    12. {
    13. RequestAufgabeNachricht = new RequestAufgabeNachricht(A_NR, istAktiveAufgabe)
    14. };
    15. Aufgabe result = null;
    16. AufgabenEventHandler handler = (object sender, AufgabeEventArgs e) =>
    17. {
    18. result = e.Aufgabe;
    19. ewh.Set();
    20. };
    21. GlobaleVariabeln.srv.AufgabenDataReceived += handler;
    22. serverProtokoll.Send();
    23. Console.WriteLine("Api ThreadID: {0}", Thread.CurrentThread.ManagedThreadId);
    24. if(result == null)
    25. ewh.WaitOne();
    26. GlobaleVariabeln.srv.AufgabenUpdated -= handler;
    27. return result;
    28. }


    Nun ist das Problem, dass wenn ich diese Funktion über ein ausgelöstes Event aufrufen will, er an der Stelle ewh.WaitOne(); dem Empfangsthread mit blockiert und ich dadurch nie eine Antwort erhalten kann.

    Siehe:

    C#-Quellcode

    1. private void Srv_AufgabenViewReceived(object sender, AufgabenListeEventArgs e)
    2. {
    3. Console.WriteLine("Miau " + Thread.CurrentThread.ManagedThreadId);
    4. Aufgabe aufgabe1 = Hilfsklassen.AufgabenGlobals.aufgabenApi.GetAufgabe(14041);
    5. if (this.InvokeRequired)
    6. {
    7. this.Invoke(new MethodInvoker(delegate ()
    8. {
    9. FillDataGridView(e.Aufgaben);
    10. Console.WriteLine("TEST " + Thread.CurrentThread.ManagedThreadId);
    11. Aufgabe aufgabe = Hilfsklassen.AufgabenGlobals.aufgabenApi.GetAufgabe(14041);
    12. }));
    13. }
    14. else
    15. {
    16. FillDataGridView(e.Aufgaben);
    17. }
    18. }


    Ich habe mir zum Test mal die Thread Ids der Funktionen ausgeben lassen. Das erste Console.WriteLine und Aufgabe aufgabe1 liefern an dieser Stelle die selbe Thread ID. Ist ja auch logisch. Das Zweite liefern dann die ID des Hauptthreads, da ja auch invoked wird.

    Falls es noch relevant sein sollte, ist hier der Code des Empfangsthreads.

    C#-Quellcode

    1. /// <summary>
    2. /// Empfängt alle Nachrichtenobjecte vom AufgabenServer
    3. /// </summary>
    4. private void Empfange()
    5. {
    6. List<byte> bytesReceived = new List<byte>();
    7. Console.WriteLine("Empfangs ThreadID: {0}", Thread.CurrentThread.ManagedThreadId);
    8. stop = false;
    9. while (IsConnected && !stop)
    10. {
    11. try
    12. {
    13. // Stream zum lesen holen
    14. while (connection.Available > 0 && connection.Connected)
    15. {
    16. isReceivingData = true;
    17. int size = (connection.Available > Int32.MaxValue) ? Int32.MaxValue : connection.Available;
    18. byte[] nextByte = new byte[size];
    19. connection.Receive(nextByte, 0, size, SocketFlags.None);
    20. bytesReceived.AddRange(nextByte);
    21. }
    22. isReceivingData = false;
    23. Thread.Sleep(100); // Nach jedem Durchgang warten wir 100ms, damit die CPU Auslastung nicht durchs permanente Abfragen bis auf 100% ansteigt!
    24. }
    25. catch (Exception ex)
    26. {
    27. Console.WriteLine(ex.Message);
    28. File.AppendAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "error.log"), ex.Message + Environment.NewLine);
    29. bytesReceived.Clear();
    30. // Setze das Schleifen-Flag zurück
    31. // wenn ein Fehler in der Kommunikation aufgetreten ist
    32. // stop = true;
    33. }
    34. // Prüfen ob eine Nachricht vollständig angekommen ist
    35. if (bytesReceived.Contains(delimiter))
    36. {
    37. // Wir müssen an dieser Stelle prüfen ob wir mehr als eine Nachricht vollständig empfangen haben.
    38. int delimiterPos = bytesReceived.IndexOf(delimiter);
    39. byte[] data = bytesReceived.GetRange(0, delimiterPos).ToArray();
    40. bytesReceived.RemoveRange(0, delimiterPos + 1);
    41. OnMessageReceived(data);
    42. }
    43. if (bytesReceived.Count == 0)
    44. {
    45. bytesReceived = new List<byte>();
    46. GC.Collect();
    47. GC.WaitForPendingFinalizers();
    48. }
    49. }
    50. // Schließe die Verbindung zum Server
    51. if (!stop) // Wenn Stop = false, dann haben wir die Verbindung unabsichtlich verloren!
    52. Disconnect();
    53. }


    Das OnMessageReceived Ereignis sieht nun wie folgt aus:

    C#-Quellcode

    1. #region Nachricht erhalten
    2. /// <summary>
    3. /// Das Event wird getriggert, wenn wir eine Nachricht vollständig empfangen haben
    4. /// </summary>
    5. /// <param name="Data"></param>
    6. protected virtual void OnMessageReceived(byte[] Data)
    7. {
    8. isReceivingData = false;
    9. string data = Encoding.UTF8.GetString(Data);
    10. if (!string.IsNullOrWhiteSpace(data))
    11. {
    12. object nachricht = NachrichtenSerializer.DeserializeObject(data);
    13. if (nachricht.GetType() == typeof(ServerProtokoll))
    14. {
    15. // Caste nachricht zu ServerProtokoll
    16. ServerProtokoll serverProtokoll = nachricht as ServerProtokoll;
    17. // Prüfe Inhalt der Nachricht
    18. if (serverProtokoll.KonfigurationsNachricht != null)
    19. {
    20. GlobaleVariabeln.IsConfigured = serverProtokoll.KonfigurationsNachricht.IsConfigured;
    21. OnKonfigurationStatusReceived(new EventArgs());
    22. }
    23. if (serverProtokoll.LoginStatusNachricht != null)
    24. {
    25. if (serverProtokoll.LoginStatusNachricht.InvalidServerProtokoll)
    26. {
    27. OnInvalidProtokollDetected(new MessageEventArgs("Die Verbindung zum AufgabenServer wurde abgebrochen, da der Client eine neuere Protokollversion verwendet.", "Bitte führen Sie ein Update des AufgabenServers durch!"));
    28. }
    29. else if (serverProtokoll.LoginStatusNachricht.InvalidClientProtokoll)
    30. {
    31. OnInvalidProtokollDetected(new MessageEventArgs("Die Verbindung zum AufgabenServer wurde abgebrochen, da der Server eine neuere Protokollversion verwendet.", "Bitte führen Sie ein Update des Clienten durch!"));
    32. }
    33. IsLoggedIn = serverProtokoll.LoginStatusNachricht.LoginErfolgreich;
    34. LizenzenVerbraucht = serverProtokoll.LoginStatusNachricht.LizenzenVerbraucht;
    35. dieserMitarbeiter = serverProtokoll.LoginStatusNachricht.VerwaltungsNachricht.DieserMitarbeiter;
    36. GlobaleVariabeln.Arbeitsgruppen = serverProtokoll.LoginStatusNachricht.VerwaltungsNachricht.Arbeitsgruppen;
    37. GlobaleVariabeln.Mitarbeiter = serverProtokoll.LoginStatusNachricht.VerwaltungsNachricht.Mitarbeiter;
    38. GlobaleVariabeln.Mitarbeiterliste = serverProtokoll.LoginStatusNachricht.VerwaltungsNachricht.Mitarbeiterliste;
    39. GlobaleVariabeln.MitarbeiterlisteAlle = serverProtokoll.LoginStatusNachricht.VerwaltungsNachricht.MitarbeiterlisteAlle;
    40. GlobaleVariabeln.SmtpHost = serverProtokoll.LoginStatusNachricht.VerwaltungsNachricht.SmtpHost;
    41. GlobaleVariabeln.SmtpUser = serverProtokoll.LoginStatusNachricht.VerwaltungsNachricht.SmtpUser;
    42. GlobaleVariabeln.SmtpPasswort = serverProtokoll.LoginStatusNachricht.VerwaltungsNachricht.SmtpPasswort;
    43. GlobaleVariabeln.SmtpPort = serverProtokoll.LoginStatusNachricht.VerwaltungsNachricht.SmtpPort;
    44. GlobaleVariabeln.SmtpUseSsl = serverProtokoll.LoginStatusNachricht.VerwaltungsNachricht.SmtpUseSsl;
    45. GlobaleVariabeln.SmtpAbsendeEmail = serverProtokoll.LoginStatusNachricht.VerwaltungsNachricht.SmtpAbsendeEmail;
    46. GlobaleVariabeln.SmtpAbsendeName = serverProtokoll.LoginStatusNachricht.VerwaltungsNachricht.SmtpAbsendeName;
    47. GlobaleVariabeln.MailVerfahren = serverProtokoll.LoginStatusNachricht.VerwaltungsNachricht.MailVerfahren;
    48. GlobaleVariabeln.DynDnsUrl = serverProtokoll.LoginStatusNachricht.VerwaltungsNachricht.DynDnsUrl;
    49. GlobaleVariabeln.Anzeigelimit = serverProtokoll.LoginStatusNachricht.VerwaltungsNachricht.Anzeigelimit;
    50. GlobaleVariabeln.DruckEnabled = serverProtokoll.LoginStatusNachricht.VerwaltungsNachricht.DruckEnabled;
    51. GlobaleVariabeln.LizenzenAktiv = serverProtokoll.LoginStatusNachricht.VerwaltungsNachricht.LizenzenAktiv;
    52. GlobaleVariabeln.ClientsLizenzsiert = serverProtokoll.LoginStatusNachricht.VerwaltungsNachricht.ClientsLizenzsiert;
    53. GlobaleVariabeln.Arbeitsgruppen = serverProtokoll.LoginStatusNachricht.VerwaltungsNachricht.Arbeitsgruppen;
    54. GlobaleVariabeln.Arbeitsgruppen = serverProtokoll.LoginStatusNachricht.VerwaltungsNachricht.Arbeitsgruppen;
    55. OnLoginStatusRecieved(new LoginEventArgs(serverProtokoll.LoginStatusNachricht.LoginErfolgreich, serverProtokoll.LoginStatusNachricht.InvalidServerProtokoll, serverProtokoll.LoginStatusNachricht.InvalidClientProtokoll));
    56. }
    57. else if (serverProtokoll.AufgabenNachricht != null) // Uns erreicht eine Benachrichtigung zu einer Aufgabe
    58. {
    59. OnAufgabenUpdated(new AufgabeEventArgs(serverProtokoll.AufgabenNachricht.Aufgabe, serverProtokoll.AufgabenNachricht.NachrichtenTyp));
    60. }
    61. else if (serverProtokoll.BearbeitenStatusNachricht != null)
    62. {
    63. OnBearbeitenStatusReceived(new BearbeitenEventArgs(
    64. serverProtokoll.BearbeitenStatusNachricht.Aufgabe,
    65. serverProtokoll.BearbeitenStatusNachricht.DarfBearbeiten,
    66. serverProtokoll.BearbeitenStatusNachricht.AnfrageAktion,
    67. serverProtokoll.BearbeitenStatusNachricht.WirdBearbeitetVonUserId
    68. ));
    69. }
    70. else if (serverProtokoll.LoginNachricht != null) // Uns erreicht eine Loginanfrage am Server
    71. {
    72. // Den Typen gibt es zwar, allerdings wird dieser ausschließlich vom Server empfangen!
    73. }
    74. else if (serverProtokoll.ServerNachricht != null) // Uns erreicht eine spezielle Nachricht des Servers
    75. {
    76. // Muss in extra Thread ausgelagert werden, da ansonsten keine weiteren Nachrichten empfangen werden können!
    77. OnServerNachrichtReceived(new MessageEventArgs(serverProtokoll.ServerNachricht.Nachricht, serverProtokoll.ServerNachricht.Title));
    78. }
    79. else if (serverProtokoll.ChatNachricht != null) // Uns erreicht eine Chatnachricht
    80. {
    81. OnChatNachrichtReceived(new ChatEventArgs(serverProtokoll.ChatNachricht.AbsenderId, serverProtokoll.ChatNachricht.EmpfängerId, serverProtokoll.ChatNachricht.AbsenderName, serverProtokoll.ChatNachricht.EmpfängerName, serverProtokoll.ChatNachricht.Nachricht));
    82. }
    83. else if (serverProtokoll.KarusselAnfrageNachricht != null)
    84. {
    85. OnKarusselAnfrage(new KarusselEventArgs(serverProtokoll.KarusselAnfrageNachricht.Aufgabe));
    86. }
    87. else if (serverProtokoll.VerwaltungsNachricht != null)
    88. {
    89. GlobaleVariabeln.Arbeitsgruppen = serverProtokoll.VerwaltungsNachricht.Arbeitsgruppen;
    90. GlobaleVariabeln.Mitarbeiter = serverProtokoll.VerwaltungsNachricht.Mitarbeiter;
    91. GlobaleVariabeln.Mitarbeiterliste = serverProtokoll.VerwaltungsNachricht.Mitarbeiterliste;
    92. GlobaleVariabeln.MitarbeiterlisteAlle = serverProtokoll.VerwaltungsNachricht.MitarbeiterlisteAlle;
    93. GlobaleVariabeln.VerbundeneUser = serverProtokoll.VerwaltungsNachricht.VerbundeneUser;
    94. this.dieserMitarbeiter = serverProtokoll.VerwaltungsNachricht.DieserMitarbeiter;
    95. // Einstellungen
    96. GlobaleVariabeln.SmtpHost = serverProtokoll.VerwaltungsNachricht.SmtpHost;
    97. GlobaleVariabeln.SmtpUser = serverProtokoll.VerwaltungsNachricht.SmtpUser;
    98. GlobaleVariabeln.SmtpPasswort = serverProtokoll.VerwaltungsNachricht.SmtpPasswort;
    99. GlobaleVariabeln.SmtpPort = serverProtokoll.VerwaltungsNachricht.SmtpPort;
    100. GlobaleVariabeln.SmtpUseSsl = serverProtokoll.VerwaltungsNachricht.SmtpUseSsl;
    101. GlobaleVariabeln.SmtpAbsendeEmail = serverProtokoll.VerwaltungsNachricht.SmtpAbsendeEmail;
    102. GlobaleVariabeln.SmtpAbsendeName = serverProtokoll.VerwaltungsNachricht.SmtpAbsendeName;
    103. GlobaleVariabeln.MailVerfahren = serverProtokoll.VerwaltungsNachricht.MailVerfahren;
    104. GlobaleVariabeln.Anzeigelimit = serverProtokoll.VerwaltungsNachricht.Anzeigelimit;
    105. // Lizensierung
    106. GlobaleVariabeln.LizenzenAktiv = serverProtokoll.VerwaltungsNachricht.LizenzenAktiv;
    107. GlobaleVariabeln.ClientsLizenzsiert = serverProtokoll.VerwaltungsNachricht.ClientsLizenzsiert;
    108. GlobaleVariabeln.DruckEnabled = serverProtokoll.VerwaltungsNachricht.DruckEnabled;
    109. OnVerwaltungsUpdate(new EventArgs());
    110. }
    111. else if (serverProtokoll.SendAufgabenNachricht != null)
    112. {
    113. OnAufgabenViewReceived(new AufgabenListeEventArgs(serverProtokoll.SendAufgabenNachricht.Aufgaben));
    114. }
    115. else if (serverProtokoll.RequestVergesseneAufgabenNachricht != null)
    116. {
    117. OnVergesseneAufgabenReceived(new VergesseneAufgabenEventArgs(serverProtokoll.RequestVergesseneAufgabenNachricht.AndereUserVergessen, serverProtokoll.RequestVergesseneAufgabenNachricht.RestAufgabenTab, serverProtokoll.RequestVergesseneAufgabenNachricht.VergesseneGruppenAufgaben, serverProtokoll.RequestVergesseneAufgabenNachricht.ShowForms));
    118. }
    119. else if (serverProtokoll.RequestAufgabeAntwortNachricht != null)
    120. {
    121. OnAufgabenDataReceived(new AufgabeEventArgs(serverProtokoll.RequestAufgabeAntwortNachricht.Aufgabe, NachrichtenTypen.AufgabeAktion.Anfragen));
    122. }
    123. else if (serverProtokoll.FiveStarWarningNachricht != null)
    124. {
    125. OnFiveStarWarningReceived(new EventArgs());
    126. }
    127. else if (serverProtokoll.RequestAntwortGruppenAufgabenNachricht != null)
    128. {
    129. OnGruppenAufgabenReceived(new GruppeLöschenEventArgs(serverProtokoll.RequestAntwortGruppenAufgabenNachricht.Gruppe, serverProtokoll.RequestAntwortGruppenAufgabenNachricht.Aufgaben));
    130. }
    131. else if (serverProtokoll.RequestMitarbeiterPunkteNachricht != null)
    132. {
    133. OnPunkteDataReceived(new PunkteEventArgs(serverProtokoll.RequestMitarbeiterPunkteNachricht.PunkteZeitraum, serverProtokoll.RequestMitarbeiterPunkteNachricht.PunkteGesamt, serverProtokoll.RequestMitarbeiterPunkteNachricht.AnzahlAufgabenVergütet, serverProtokoll.RequestMitarbeiterPunkteNachricht.PunkteVerlauf));
    134. }
    135. else if (serverProtokoll.RequestMitarbeiterAuslastungNachricht != null)
    136. {
    137. OnAuslastungsDataReceived(new AuslastungEventArgs(serverProtokoll.RequestMitarbeiterAuslastungNachricht.AufgabenZuerledigen));
    138. }
    139. else if(serverProtokoll.ErrorNachricht != null)
    140. {
    141. //TODO: Event auslösen
    142. }
    143. else if(serverProtokoll.StatusNachricht != null)
    144. {
    145. OnStatusReceived(new StatusEventArgs(
    146. serverProtokoll.StatusNachricht.Message,
    147. serverProtokoll.StatusNachricht.Status));
    148. }
    149. else
    150. {
    151. // Es handelt sich zwar um ein übermitteltes Serverprotokoll, allerdings haben wir bis hier hin keinen Inhalt gefunden
    152. // Das bedeutet, dass uns ein Nachrichtentyp einer nicht unterstützen Revision erreicht hat!
    153. }
    154. serverProtokoll.Dispose();
    155. }
    156. else
    157. {
    158. // Uns erreicht ein unbekanntes Flugobject!
    159. }
    160. }
    161. }




    Habt Ihr vielleicht einen Tipp, wie ich dieses Problem lösen kann?

    Viele Grüße,
    Marvin

    MarvinKleinMusic schrieb:

    Nun ist das Problem, dass wenn ich diese Funktion über ein ausgelöstes Event aufrufen will, er an der Stelle ewh.WaitOne(); dem Empfangsthread mit blockiert und ich dadurch nie eine Antwort erhalten kann.
    Mir scheint daraus zu folgen, du solltest im EmpfangsThread eben nicht ewh.WaitOne(); aufrufen - oder?
    Hallo @ErfinderDesRades

    ja, dass ist klar. Was mich nur gewundert hat ist, dass ich trotz Invoke in dem Event scheinbar den Empfnagsthread mitblockiert habe, obwohl die Funktion nach dem Invoke sogar die richtige Thread ID ausgegeben hat.

    Ich habe das Problem nun relativ simple gelöst. Sobald eine Nachricht empfangen wurde, wird das Event für Nachricht empfangen einfach in einem neuen Thread ausgeführt.

    LG Marvin

    MarvinKleinMusic schrieb:

    Was mich nur gewundert hat ist, dass ich trotz Invoke in dem Event scheinbar den Empfnagsthread mitblockiert habe
    Jo, das finde ich dem geposteten Code auch nicht so ohne weiteres abzusehen - vermutlich iwelche Fehler in Abhängigkeiten, im srv, oder im ServerProtokoll oder sonstwo.
    Dieses hier betrachte ich auch mit äusserstem Misstrauen:

    C#-Quellcode

    1. //...
    2. if (bytesReceived.Count == 0)
    3. {
    4. //...
    5. GC.Collect();
    6. GC.WaitForPendingFinalizers();
    7. }
    8. //...
    Bist du sicher, dass du weisst, was da passiert?
    Und wozu das notwendig ist?
    Wenn nicht, machs weg.

    Wenn du mittm GC herumhantierst, sollteste dich eingehend informieren, was der tut, und wie, und welche Manipulation was bewirkt.
    Und die Informationen auch durch eigene Experimente nachprüfen.
    Wenn dir die Informationen "zu hoch" sind, empfehle ich, die Finger davon zu lassen.
    Mir zum Beispiel waren die Artikel, die ich zum Thema fund, meist zu hoch.
    Alles was ich mir davon gemerkt habe, war, dass der GC ausgebuffte Algorithmen verwendet, deren Performance sich durch externe Eingriffe verschlechtern soll.
    Das finde ich logisch nachvollziehbar, wenn auch ich es nicht durch Experimente bestätigt habe.
    Ich lasse einfach die Finger davon, und bin bislang noch auf kein Problem gestossen, was durch "GC-Hacks" zu lösen gewesen wäre.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Hallo @ErfinderDesRades

    Der grund warum ich den GarbageCollector manuell anspreche ist ganz leicht zu verstehen.

    Über dem Empfangsthread werden alle empfangenen Bytes zu einer List<byte> hinzugefügt. Sobald eine Nachricht vollständig empfangen wurde, erkennbar am Delimiter Byte 0x13 werden alle Bytes von der Nachricht aus der Liste gelöscht und an die Funktion MessageReceived übergeben. Das Problem an dieser Funktionsweise ist, dass Listen nicht direkt den Speicher wieder freigeben, wenn ich aus denen Werte entferne.

    Da ich an dieser Stelle aber auch zum Teil sehr große Objekte empfange, würde das Programm so z.B. mehrere GB an Arbeitsspeicher verbrauchen. Dies umgehe ich damit, dass immer wenn die Liste leer wird, ich den GarbageCollector aufräumen lasse.

    LG Marvin
    Ist das wirklich so?
    Imo dürfte die List<byte> niemals wesentlich über den Umfang des grössten empfangenen Objektes hinauswachsen, und wenn das Objekt numa Gigabyte groß ist, dann wird dieser Speicher eben gebraucht - da hilft auch kein gc.Collect(), und schon garkein .WaitForPendingFinalizers().
    Wie gesagt: Hast du dich informiert, was speziell letztere Methode tut, und wie sie sich in Multithreading-Umgebungen verhält - nicht dass da etwa ein Deadlock entsteht, weil sie auf einen Finalizer wartet, der in einem angehaltenem Thread auszuführen ist?

    Weiters solltest du überlegen, ob du die Architektur auf Streams umstellen kannst. List<byte> gigabyte-weise zu verwenden scheint mir ein extremer System-Stressor, den es möglichst zu vermeiden gilt.
    Hallo nochmal,

    Imo dürfte die List<byte> niemals wesentlich über den Umfang des grössten empfangenen Objektes hinauswachsen


    Das stimmt so nicht, da der Client zum Teil mehrere Objekte hintereinander übermittelt, diese aber bereits über Connection.Available empfangen werden. So kann es sein, dass in der Liste mehrere Nachrichten drin sind.

    Vielen Dank für den Hinweis, dass dürfte auch erklären, wieso es manchmal zu den Deadlocks gekommen ist. Ich werde das mal überarbeiten. Ich fände es ohne List auch wesentlich besser doch wie soll ich mittels eines Streams umsetzen?

    LG Marvin

    MarvinKleinMusic schrieb:

    Vielen Dank für den Hinweis, dass dürfte auch erklären, wieso es manchmal zu den Deadlocks gekommen ist.
    Ähm - es könnte erklären. Beachte: Ich hab keine Ahnung, wie .WaitForPendingFinalizers sich auswirkt, meine Äusserungen dazu sind spekulative Assoziationen - weil die Methode ja auf etwas zu warten scheint.



    Warum mehrere Objekte nu zwingend in einer byte-Liste sein müssen, und dass das nicht zu ändern ist, habich jetzt nicht verstanden - die Formulierung "über Connection.Available empfangen" ergibt nach meim Begriffs-Verständnis keinen Sinn.



    MarvinKleinMusic schrieb:

    wie soll ich mittels eines Streams umsetzen?
    Ich weiss nicht, was du machst, wie soll ich dir dann sagen, wie du es mittels eines Streams umsetzen sollst?
    Ich weiss nur, dass Streams dazu da sind, beliebig grosse Datenmengen häppchenweise zu bewegen, sodass man nicht Speicherplatz alloziieren muss, der das gesamte Datenvolumen auf einmal aufnimmt.
    Weiters gibt es Serialisierer, die Objekte in Streams transformieren und zurück.
    Weiters gibts bei Tcp die NetworkStream-Klasse, sodass man also auch beliebig grosse Datenmengen übers Internet transportieren kann.
    Mir scheint damit ein Instrumentarium gegeben, mit dem du dir was zusammenbasteln können müsstest, bei dem keine Speicherplatz-Probleme auftauchen - ausser etwa es geht um Gigabyte-grosse Bitmaps in einem Stück.

    Ach, und im Tutorial-Bereich gibts ein Tut zu den Stream-Konzepten: Streams