Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ConcurrentStack: How to check if contains object?

Tags:

c#

How can i check if it contains specific object in the stack ?

private ConcurrentStack<int> cs = new ConcurrentStack<int>();
cs.Push(1);
like image 587
James Coleman Avatar asked Sep 16 '26 10:09

James Coleman


2 Answers

The method Stack<T>.Contains isn't available in the ConcurrentStack<T>-class. I guess because that would not be thread-safe.

So if you needed it you had to use a lock, then you could use Enumerable.Contains:

private ConcurrentStack<int> cs = new ConcurrentStack<int>();
private Object csLockObject  = new Object();

...

bool contains = false;
lock (csLockObject)
{
    contains = cs.Contains(1);
}

But while you enumerate this snapshot it's possible that another thread adds or removes items to/from the stack. If you wanted to prevent that you also need a lock where you add/remove.

I want to avoid duplicates

Well, you could use a class like this which uses a ConcurrentDictionary to check if it's unique:

public class ConcurrentUniqueStack<T>
{
    private readonly ConcurrentDictionary<T, int> _itemUnique; // there is no ConcurrentHashSet so we need to use a Key-only dictionary
    private readonly ConcurrentStack<T> _stack;

    public ConcurrentUniqueStack() : this(EqualityComparer<T>.Default)
    {
    }
    public ConcurrentUniqueStack(IEqualityComparer<T> comparer)
    {
        _stack = new ConcurrentStack<T>();
        _itemUnique = new ConcurrentDictionary<T, int>(comparer);
    }

    public bool TryPush(T item)
    {
        bool unique = _itemUnique.TryAdd(item, 1);
        if (unique)
        {
            _stack.Push(item);
        }

        return unique;
    }
    public bool TryPop(out T result)
    {
        bool couldBeRemoved = _stack.TryPop(out result);
        if (couldBeRemoved)
        {
            _itemUnique.TryRemove(result, out int whatever);
        }
        return couldBeRemoved;
    }

    public bool TryPeek(out T result) => _stack.TryPeek(out result);
}
like image 125
Tim Schmelter Avatar answered Sep 18 '26 00:09

Tim Schmelter


This structure is not optimized for this operation.

It means, that value lookup operation has O(N) complexity, because you have to iterate whole collection.

So answer depends of your requirements:

  • If you want to check value sometimes (e.g. complexity is does not matter) - just use _stack.FirstOrDefault(v=> v==valueWhichYouTryToFind). This can be slow, because you have to iterate all elements. However task will be solved. And please note, that stack can be changed before this function will be finished (e.g. this function can return true after stack pop operation will be finished)
  • If you want to often check values inside huge stack - then you have to create complex structure with concurrent set + stack. I recommend (this is just my opinion) to use just simple Stack + HashSet + locks, because it is quite simpler.
like image 26
Manushin Igor Avatar answered Sep 17 '26 22:09

Manushin Igor