2017-12-21 9 views
0

Ich habe eine C# App. Es gibt eine Stack-Sammlung, die verwendet wird.Bin ich garantiert einen Wert von einem TryPop gegen einen ConcurrentStack

Jetzt ist dieser Sammlung Zugriff von vielen Threads und so muss ich es Thread-Safe machen.

Also schaue ich stattdessen mit einer ConcurrentStack Collection.

Nun verwendet dies TryPeek, TryPop, TryPush und es gibt eine True/False-Flag, um Erfolg zu signalisieren oder nicht.

Wird mit diesem Flag erkannt, ob ein Objekt in der Auflistung vorhanden ist oder nicht, weil es möglicherweise fehlschlägt, weil ein anderer Thread gleichzeitig auf die Auflistung zugreift und die Aktion erneut versucht werden muss?

+2

Die Dokumentation besagt, dass "false" zurückgegeben wird, wenn die Sammlung kein Element zum Entfernen und Zurückgeben enthält. – Amy

+0

@amy danke für diese Bestätigung –

+0

Ich bin unklar, was Sie hier fragen möchten. Aber nur für den Fall, dass Sie unsicher sind - Sie haben bereits festgestellt, dass dies Multithread-Zugriff ist. Jede * Argumentation *, die Sie bei irgendwelchen Rückgabewerten durchführen, ist * irrelevant * für den Zustand der Sammlung, wenn Sie das nächste Mal versuchen, darauf zuzugreifen. –

Antwort

2

Hier ist der Quellcode für ConcurrentStack.TryPop<T>() (wie durch ILSpy dekompilierten):

public bool TryPop(out T result) 
{ 
    ConcurrentStack<T>.Node head = this.m_head; 
    if (head == null) 
    { 
     result = default(T); 
     return false; 
    } 
    if (Interlocked.CompareExchange<ConcurrentStack<T>.Node>(ref this.m_head, head.m_next, head) == head) 
    { 
     result = head.m_value; 
     return true; 
    } 
    return this.TryPopCore(out result); 
} 

Diese Methode liefert false wenn der Gegenstand nicht entfernt werden kann/zurückgegeben, oder wenn TryPopCore kehrt false. Also hier ist, dass:

private bool TryPopCore(out T result) 
{ 
    ConcurrentStack<T>.Node node; 
    if (this.TryPopCore(1, out node) == 1) 
    { 
     result = node.m_value; 
     return true; 
    } 
    result = default(T); 
    return false; 
} 

so dass gibt zurück, ob TryPopCore(int, out ConcurrentStack<T>.Node) erfolgreich ist:

private int TryPopCore(int count, out ConcurrentStack<T>.Node poppedHead) 
{ 
    SpinWait spinWait = default(SpinWait); 
    int num = 1; 
    Random random = new Random(Environment.TickCount & 2147483647); 
    ConcurrentStack<T>.Node head; 
    int num2; 
    while (true) 
    { 
     head = this.m_head; 
     if (head == null) 
     { 
      break; 
     } 
     ConcurrentStack<T>.Node node = head; 
     num2 = 1; 
     while (num2 < count && node.m_next != null) 
     { 
      node = node.m_next; 
      num2++; 
     } 
     if (Interlocked.CompareExchange<ConcurrentStack<T>.Node>(ref this.m_head, node.m_next, head) == head) 
     { 
      goto Block_5; 
     } 
     for (int i = 0; i < num; i++) 
     { 
      spinWait.SpinOnce(); 
     } 
     num = (spinWait.NextSpinWillYield ? random.Next(1, 8) : (num * 2)); 
    } 
    if (count == 1 && CDSCollectionETWBCLProvider.Log.IsEnabled()) 
    { 
     CDSCollectionETWBCLProvider.Log.ConcurrentStack_FastPopFailed(spinWait.Count); 
    } 
    poppedHead = null; 
    return 0; 
    Block_5: 
    if (count == 1 && CDSCollectionETWBCLProvider.Log.IsEnabled()) 
    { 
     CDSCollectionETWBCLProvider.Log.ConcurrentStack_FastPopFailed(spinWait.Count); 
    } 
    poppedHead = head; 
    return num2; 
} 

Wie Sie sehen können, ist es falsch zurück, wenn es nicht ein Element entfernen und sie dann zurück. Es gibt eine Menge zu dieser letzten Funktion, und der dekompilierte Code ist nicht der sauberste, aber er scheint der Dokumentation zu entsprechen.

+0

Danke. Ich hetze jetzt von der Arbeit und werde es mir ansehen, wenn ich zurück bin. Danke noch einmal. –

Verwandte Themen