简体   繁体   English

填充ConcurrentDictionary时的C#静态构造函数初始化线程安全

[英]C# static constructor initialization thread safety while filling ConcurrentDictionary

I'm calling var person = PersonDB.pDict["395096"]; 我叫var person = PersonDB.pDict["395096"];

Can anyone explain me why this code blocks: 谁能解释一下为什么此代码会阻止:

static class PersonDB
{
    internal static readonly ConcurrentDictionary<string, Person> pDict;

    static PersonDB()
    {
        pDict = new ConcurrentDictionary<string, Person>();
        var headers = File.ReadLines(FindPath.DataSetPerson).First().Split(';');


        File.ReadLines(FindPath.DataSetPerson).AsParallel().Skip(1).Select(s => s.Split(';')).ForAll(fa =>
           pDict.TryAdd(fa[0], new Person() { all = Enumerable.Range(0, fa.Length).ToDictionary(t => headers[t], d => fa[d]) })
        );
    }
}

sealed class Person
{
    public Dictionary<string, string> all;
}

While this part does not block: 虽然这部分不会阻止:

static class PersonDB
{
    internal static readonly ConcurrentDictionary<string, Person> pDict;

    static PersonDB()
    {
        pDict = new ConcurrentDictionary<string, Person>();
        var headers = File.ReadLines(FindPath.DataSetPerson).First().Split(';');


        //File.ReadLines(FindPath.DataSetPerson).AsParallel().Skip(1).Select(s => s.Split(';')).ForAll(fa =>
        //   pDict.TryAdd(fa[0], new Person() { all = Enumerable.Range(0, fa.Length).ToDictionary(t => headers[t], d => fa[d]) })
        //);

        Parallel.ForEach(File.ReadLines(FindPath.DataSetPerson).Skip(1).Select(s => s.Split(';')), line =>
        {
            pDict.TryAdd(line[0], new Person() { all = Enumerable.Range(0, line.Length).ToDictionary(t => headers[t], d => line[d]) });
        });

    }
}

sealed class Person
{
    public Dictionary<string, string> all;
}

To be honest I'm not even sure if the latter is thread safe now, but at least it runs without problems. 老实说,我什至不确定后者现在是否是线程安全的,但至少它运行没有问题。 I would like to know how to make the PersonDB a thread safe class in such a way that there will be no race conditions or deadlocks. 我想知道如何使PersonDB成为线程安全类,这样就不会出现争用条件或死锁。 The pDict needs to be created once on usage of the pDict. 使用pDict时,只需创建一次pDict。 I thought the static constructor was a nice solution for this but the execution stop on the PLINQ query makes me very unsure... 我以为静态构造函数是一个不错的解决方案,但是PLINQ查询的执行停止使我非常不确定...

This is a static constructor deadlock. 这是一个静态构造函数死锁。 The parallel threads access PersonDB which blocks until PersonDB is statically initialized. 并行线程访问PersonDB ,后者阻塞直到PersonDB被静态初始化。 Move the initialization code to a different function. 将初始化代码移到其他函数。 Make it return the dictionary instead of modifying pDict in place. 使它返回字典,而不是就地修改pDict

I try to avoid static constructors that do things that can fail. 我尽量避免执行可能会失败的静态构造函数。 Your code certainly can fail because it is IO. 您的代码肯定会失败,因为它是IO。 If it does the class is permanently hosed. 如果是这样,则该类将永久固定。 Lazy can be better. Lazy可以更好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM