Entwickler-Ecke
Sonstiges (.NET) - Mehrere Threads auf eine Liste zugreifen
marian04 - Do 29.11.12 11:53
Titel: Mehrere Threads auf eine Liste zugreifen
Hallo an alle Forenmitgleider,
ich habe zur Zeit ein kleines Problem mit einer Liste und Multithreading, aber lasst es mich kurz ein wenig ausführlicher beschreiben:
Ich habe einen TCP Listener, der auf den Port 3000 hört und dort abwartet, bis eine bestimmte Information reinkommt.
Dieser Listener schreibt die erhaltenen Informationen in ein Objekt und legt dieses in einer Liste ab. (Thread 1)
Dieser Thread läuft natürlich dauerhaft und wartet IMMER auf Informationen die auf diesem Port eintreffen.
Nun möchte ich diese Liste automatisch durchgehen und zu einer bestimmten Zeit einen weiteren Event auslösen. Der Zeitpunkt, zu welchem der Event ausgelöst werden soll, ist in dem Objekt gespeichert.
Nun zu meinem Problem:
Ich durchlaufe diese Liste mit einer Foreach-Schleife und diese führt wohl zu Fehler, ich weiß mir aber leider nicht zu helfen, wieso genauer dieser Fehler auftritt und wie ich diesen umgehen kann.
Anbei der Code:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| private void readList() { System.Diagnostics.Debug.WriteLine("reader");
while(true) { foreach (var aufnahmen in aufList) { System.Diagnostics.Debug.WriteLine(DateTime.UtcNow.ToUniversalTime().ToString("yyyy''MM''dd''HH''mm"));
if (DateTime.UtcNow.ToString() == aufnahmen.startTime) { System.Diagnostics.Debug.WriteLine("Aufnahme gefunden"); }
System.Diagnostics.Debug.WriteLine("Schleife durchlaufen"); } } } |
Und hier der Fehler:
Quelltext
1:
| Eine Ausnahme (erste Chance) des Typs "System.InvalidOperationException" ist in mscorlib.dll aufgetreten. |
Beste Grüße,
Marian
Moderiert von
Christian S.: Code- durch C#-Tags ersetzt
Moderiert von
Th69: Beitragsformatierung überarbeitet: überflüssige Leerzeilen entfernt
Ralf Jansen - Do 29.11.12 12:01
Andert sich die aufList List während du per foreach darüber iterierst? Das wäre nicht zulässig. (Obwohl sich das eigentlich in einer anderen Exception äußern sollte)
Wenn sich die einzelne Instanz in der Liste nicht ändert kannst du einfach Threadsicherheit erreichen indem du über eine Kopie der Liste iterierst.
C#-Quelltext
1:
| foreach (var aufnahmen in new List<WasAuchImmer>(aufList)) |
marian04 - Do 29.11.12 12:05
Hallo Ralf,
ja die Liste würde sich ändern, denn jedes mal, wenn jemand eine Anfrage an den Port sendet wird ein neues Objekt der Liste hinzugefügt.
Würde eine Kopie der Liste nicht dazu führen, dass ich immer mit einer "alten" Liste arbeite und mir aufgrund dessen neu hinzugekommene Objekte entgehen ?
Beste Grüße,
Marian
Ralf Jansen - Do 29.11.12 12:19
Zitat: |
Würde eine Kopie der Liste nicht dazu führen, dass ich immer mit einer "alten" Liste arbeite und mir aufgrund dessen neu hinzugekommene Objekte entgehen ? |
Das ist genau der Sinn der Kopie. Einen Snapshot zu haben der sich nicht mehr ändert und damit Threadsafe ist.
Wenn du etwas anderes willst wird es komplizierter. Das wird entweder darauf hinauslaufen Listenzugriffe mit Locks/Mutexen/ReadWriterLocks zu serialisieren oder anstatt eine Liste ein Queue oder ähnliches zu benutzen. Gibt bestimmt auch noch ein paar andere Wege. Welcher der richtige ist hängt davon ab wie sich der Rest Code verhält also wie und wann sich deine Liste verändert. Da müßte man den gesamten Code betrachten um irgendwas vorzuschlagen.
marian04 - Do 29.11.12 12:22
An der Gesamtübersicht soll es nicht liegen:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190:
| using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading;
namespace AufnahmenVerwaltungWowza { class Program { static void Main(string[] args) { Server server = new Server();
Console.ReadKey(); } } class Server { private TcpListener tcpListener; private Thread listenThread; private Thread listChecker; public List<Aufnahmen> aufList = new List<Aufnahmen>();
public Server() {
this.tcpListener = new TcpListener(IPAddress.Any, 3000); this.listenThread = new Thread(new ThreadStart(ListenForClients)); this.listChecker = new Thread(new ThreadStart(readList)); this.listenThread.Start(); this.listChecker.Start(); }
private void ListenForClients() { this.tcpListener.Start();
while (true) { TcpClient client = this.tcpListener.AcceptTcpClient();
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm)); clientThread.Start(client); } }
private void HandleClientComm(object client) { TcpClient tcpClient = (TcpClient)client; NetworkStream clientStream = tcpClient.GetStream();
byte[] message = new byte[4096]; int bytesRead;
while (true) { bytesRead = 0;
try { bytesRead = clientStream.Read(message, 0, 4096); } catch { break; }
if (bytesRead == 0) { break; }
ASCIIEncoding encoder = new ASCIIEncoding(); string[] incomingRecording = encoder.GetString(message).Split('#'); Aufnahmen aufnahmen = new Aufnahmen(Convert.ToString(incomingRecording[0]), Convert.ToString(incomingRecording[1]), Convert.ToString(incomingRecording[2]), Convert.ToString(incomingRecording[3]),Convert.ToString(incomingRecording[4])); System.Diagnostics.Debug.WriteLine(encoder.GetString(message, 0, bytesRead)); aufList.Add(aufnahmen); }
tcpClient.Close(); }
private void readList() {
System.Diagnostics.Debug.WriteLine("reader"); while(true) { foreach (var aufnahmen in aufList) { System.Diagnostics.Debug.WriteLine(DateTime.UtcNow.ToUniversalTime().ToString("yyyy''MM''dd''HH''mm")); if (DateTime.UtcNow.ToString() == aufnahmen.startTime) { System.Diagnostics.Debug.WriteLine("Aufnahme gefunden"); startRecording(aufnahmen); } System.Diagnostics.Debug.WriteLine("test"); }
}
}
private void startRecording(Aufnahmen recording) { CookieContainer cJar; string UserAgent = @"Mozilla/5.0 (Windows; Windows NT 6.1) AppleWebKit/534.23 (KHTML, like Gecko) Chrome/11.0.686.3 Safari/534.23"; HttpWebRequest startRequest = (HttpWebRequest)WebRequest.Create("http://svtv002:8086/livestreamrecord?app=live&streamname=" + recording.Channel + "&action=startRecording&user="+recording.User+"&output=/"+recording.User+"_"+recording.Channel+"_"+recording.Titel+"flv"); startRequest.UserAgent = UserAgent; startRequest.KeepAlive = false; startRequest.Method = "GET"; HttpWebResponse response = (HttpWebResponse)startRequest.GetResponse(); StreamReader sr = new StreamReader(response.GetResponseStream()); string response1 = sr.ReadToEnd(); }
private void stopRecording() { } } class Aufnahmen { private string user; private string channel; public string startTime; private string endTime;
public string User { get { return user; } set { user = value; } }
public string Channel { get { return channel; } set { channel = value; } }
public string StartTime { get { return startTime; } set { startTime = value; } }
public string EndTime { get { return endTime; } set { endTime = value; } }
public string Titel { get { return titel; } set { titel = value; } }
private string titel;
public Aufnahmen(string user, string channel, string startTime, string endTime, string titel) { this.user = user; this.channel = channel; this.startTime = startTime; this.endTime = endTime; this.titel = titel; }
} } |
Beste Grüße
Moderiert von
Christian S.: Code- durch C#-Tags ersetzt
Ralf Jansen - Do 29.11.12 12:57
Kommen da immer nur Aufnahmen hinzu? Oder sollen die auch irgendwann aus der Liste rausfallen?
marian04 - Do 29.11.12 13:11
Diese Aufnahmen müssen auch wieder gestoppt werden und fallen damit dann aus der Liste raus.
Das wäre dann der Endzeitpunkt der in der class Aufnahmen gespeichert ist.
Ralf Jansen - Do 29.11.12 13:36
Dann gehe mal davon aus das die Liste immer relativ kurz ist (keine Tausenden). Dann würde ich weiterhin mit der Kopie der Liste arbeiten. Jeder Schleifendurchlauf dauert ja vorraussichtlich nur Millisekunden. Wenn dann die Anzeige im schlimmstenfall den Zustand von vor ein paar Millisekunden darstellt kann der betrachtende User das eh nicht unterscheiden. Da macht jeder zusätzliche Aufwand das ~genauer~ darzustellen auch keinen Sinn. Die ReadList() Methode solltest du selbst noch etwas ausbremsem. Das die in Endlosschleife die Liste ausgibt die sich vermutlich nicht so schnell ändert wird dir einen Core deines Prozessors unnötigerweise zu annähern 100% auslasten. Entweder da einen Sleep() einbauen oder keinen echten Thread nehmen sondern einen Threaded Timer der nur in einem sinnvollen zeitlichen Abstand mal die Liste ausgibt.
marian04 - Do 29.11.12 13:41
Okay.
Danke für die Info.
Die Liste soll so und so nicht ausgeben werden. Das Programm wird ohne Gui und ohne weiteren Einfluss des Users laufen.
Ich werde das einfach mal probieren mit der Liste.
Beste Grüße
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!