Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ConcurrentBag of strings and using .Contains in Parallel.ForEach

Im using the ConcurrentBag to contain a list of strings. Occasionally it will contain a duplicate.

However im checking the contents of this before adding the new entry so it should never have a duplicate.

ConcurrentDictionary<string, string> SystemFiles = PopulateSystemFiles();
ConcurrentBag<string> SystemNames = new ConcurrentBag<string>();

Parallel.ForEach(SystemFiles, file =>
{
    string name = GetSystemName(file.Value);

    if (!SystemNames.Contains(name))
    {
        SystemNames.Add(name);
    }
});

My assumpion is that the .Contains method is not thread safe. Am i correct?

like image 944
CathalMF Avatar asked Nov 15 '25 01:11

CathalMF


1 Answers

ConcurrentBag is threadsafe, but your code isn't:

if (!SystemNames.Contains(name))
{
    SystemNames.Add(name);
}

Contains will execute in a thread-safe way, then Add will also execute in a thread-safe way, but you have no guarantee that an item haven't been added in-between.

For your needs, I recommend using a ConcurrentDictionary instead. Just ignore the value as you won't need it.

var SystemNames = new ConcurrentDictionary<string, bool>();

Then use the TryAdd method to do the "if not contains then add" in a single atomic operation:

SystemNames.TryAdd(name, true);
like image 72
Kevin Gosse Avatar answered Nov 17 '25 16:11

Kevin Gosse