ConcurrentBag 字符串并在 Parallel.ForEach 中使用 .Contains

Cat*_*lMF 1 c# parallel-processing concurrency multithreading thread-safety

我使用 ConcurrentBag 来包含字符串列表。有时它会包含一个副本。

但是我在添加新条目之前检查了它的内容,所以它不应该有重复。

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);
    }
});
Run Code Online (Sandbox Code Playgroud)

我的假设是 .Contains 方法不是线程安全的。我对么?

Kev*_*sse 6

ConcurrentBag 是线程安全的,但您的代码不是:

if (!SystemNames.Contains(name))
{
    SystemNames.Add(name);
}
Run Code Online (Sandbox Code Playgroud)

Contains将以线程安全的方式Add执行,然后也将以线程安全的方式执行,但您不能保证中间没有添加项目。

根据您的需要,我建议使用 aConcurrentDictionary代替。只需忽略该值,因为您不需要它。

var SystemNames = new ConcurrentDictionary<string, bool>();
Run Code Online (Sandbox Code Playgroud)

然后使用该TryAdd方法在单个原子操作中执行“如果不包含则添加”:

SystemNames.TryAdd(name, true);
Run Code Online (Sandbox Code Playgroud)