我保证从TryPop获得一个针对ConcurrentStack的值

问题描述 投票:0回答:1

我有一个C#应用程序。有一个Stack集合使用。

现在,这个集合正在从许多线程访问,所以我需要使它成为线程安全。

所以,我正在考虑使用ConcurrentStack Collection。

现在这使用TryPeek,TryPop,TryPush,它返回一个True / False标志来表示成功与否。

此标志是否识别对象是否存在于集合中,还是因为它可能会失败,因为另一个Thread同时访问该集合并且我需要重新尝试该操作?

c# multithreading
1个回答
2
投票

以下是ConcurrentStack.TryPop<T>()的源代码(由ILSpy反编译):

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);
}

当无法移除/返回项目时,或者当false返回TryPopCore时,此方法返回false。所以这就是:

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;
}

因此,返回TryPopCore(int, out ConcurrentStack<T>.Node)是否成功:

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;
}

如您所见,如果无法删除项目然后将其返回,则返回false。这最后一个函数有很多,反编译的代码并不是最干净的,但它似乎符合文档所述的内容。

© www.soinside.com 2019 - 2024. All rights reserved.