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

标签 c# multithreading thread-safety plinq static-constructor

我正在调用 var person = PersonDB.pDict["395096"];

谁能解释一下为什么这段代码会阻塞:

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

虽然这部分没有阻塞:

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

老实说,我什至不确定后者现在是否是线程安全的,但至少它运行没有问题。我想知道如何使 PersonDB 成为线程安全类,从而不会出现竞争条件或死锁。 pDict 需要在使用 pDict 时创建一次。我认为静态构造函数是一个很好的解决方案,但是 PLINQ 查询的执行停止让我非常不确定......

最佳答案

这是静态构造函数死锁。并行线程访问 PersonDB,它会阻塞,直到 PersonDB 被静态初始化。将初始化代码移动到不同的函数。让它返回字典,而不是就地修改 pDict

我尽量避免执行可能会失败的静态构造函数。您的代码肯定会失败,因为它是 IO。如果确实如此,则该类将被永久性地清洗。 Lazy 可以更好。

关于C# 静态构造函数在填充 ConcurrentDictionary 时初始化线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31829613/

相关文章:

c# - 线程 sleep C#

java - sleep 线程唤醒后会发生什么?

java - AtomicInteger 和 volatile

Java swing UI线程和事件按钮事件

c# - 如何在 C# 中处理双重解析中的文化?

c# - DoTween repeatType.yoyo 在 Sequence 中不起作用

c# - 在数据绑定(bind)范围内创建一个变量

java - 套接字关闭后杀死线程

java - 使用同步方法测试两个线程递增单个int的结果令人困惑

c# - 是否可以在 MS Surface 上运行 Perl 脚本?