ConcurrentDictionary mit mehreren Werten pro Schlüssel, wobei leere Einträge entfernt werden
Posted: 08 Jan 2025, 08:03
ConcurrentDictionary eignet sich gut für gleichzeitige Situationen, in denen Schlüssel jeweils einem einzelnen Wert zugeordnet werden. Bei der Zuordnung zu mehreren Werten ist es einfach, ein ConcurrentDictionary zu erstellen und dessen Hinzufügungs-/Entfernungsfunktionen zu schützen.
Allerdings wurde oben davon ausgegangen, dass leere Listen verbleiben dürfen. Das will ich nicht. Aber das Entfernen leerer Paare scheint auf atomare Weise nicht möglich zu sein. Man könnte versuchen:
Aber dies hat eine Race-Bedingung, wenn ein anderer Thread die Liste zuvor erfasst, sie aber ergänzt, nachdem sie geleert und an anderer Stelle entfernt wurde:
Soweit ich das beurteilen kann, würde eine Lösung normalerweise mithilfe von Vergleichs- und Austauschoperationen und dem Ersetzen der Liste durch z. B. gefunden werden. ein unveränderliches Array, das dann vollständig ersetzt wird. Da ConcurrentDictionary jedoch kein TryRemove mit einem erwarteten-Wert zum Vergleich anbietet, verstehe ich nicht ganz, wie das geht. Möglicherweise gibt es eine zweistufige Lösung?
Die Verwendung des out-Parameters von TryRemove zum erneuten Hinzufügen von Werten nach dem Entfernen (um Race-Fälle zu beheben) ist nicht möglich - Das Wörterbuch wäre kurzzeitig in einem inkonsistenten Zustand.
Auf dieser Website gibt es viele Fragen zu ähnlichen Szenarien, aber die meisten davon weisen triviale Fehler auf oder werden nicht entfernt leere Einträge. Es gibt diese sehr verwandte Frage, die fragt, ob dies möglich ist. Leider ist es fünf Jahre alt, hat sehr wenig Beachtung gefunden und es gibt keine andere Lösung als den Rückgriff auf Schlösser (was seinen Zweck zunichte macht). Möglicherweise hat sich seitdem ein besserer Weg ergeben.
(Beispiel zur Verdeutlichung bearbeitet)
Code: Select all
ConcurrentDictionary d;
// Add
var list = d.GetOrAdd ("key", x => new List ());
lock (list) {
list.Add ("value to add");
}
// Remove
if (d.TryGetValue ("key", out var list)) {
lock (list) {
list.Remove ("value to remove");
}
}
Code: Select all
if (d.TryGetValue ("key", out var list)) {
lock (list) {
if (list.Remove ("value to remove") && list.Count == 0) {
d.TryRemove ("key", out _);
}
}
}
- A: Liste abrufen
- B: Liste abrufen
- B: sperren, aus Liste entfernen< /li>
B: Liste ist leer, Schlüssel löschen, entsperren - A: Sperren, zur Liste hinzufügen, entsperren
Soweit ich das beurteilen kann, würde eine Lösung normalerweise mithilfe von Vergleichs- und Austauschoperationen und dem Ersetzen der Liste durch z. B. gefunden werden. ein unveränderliches Array, das dann vollständig ersetzt wird. Da ConcurrentDictionary jedoch kein TryRemove mit einem erwarteten-Wert zum Vergleich anbietet, verstehe ich nicht ganz, wie das geht. Möglicherweise gibt es eine zweistufige Lösung?
Die Verwendung des out-Parameters von TryRemove zum erneuten Hinzufügen von Werten nach dem Entfernen (um Race-Fälle zu beheben) ist nicht möglich - Das Wörterbuch wäre kurzzeitig in einem inkonsistenten Zustand.
Auf dieser Website gibt es viele Fragen zu ähnlichen Szenarien, aber die meisten davon weisen triviale Fehler auf oder werden nicht entfernt leere Einträge. Es gibt diese sehr verwandte Frage, die fragt, ob dies möglich ist. Leider ist es fünf Jahre alt, hat sehr wenig Beachtung gefunden und es gibt keine andere Lösung als den Rückgriff auf Schlösser (was seinen Zweck zunichte macht). Möglicherweise hat sich seitdem ein besserer Weg ergeben.
(Beispiel zur Verdeutlichung bearbeitet)