NpgsqlConnection.Open 在对 Monitor.Enter 的 Npgsql.ConnectorPool.Allocate() 调用中被阻止

NpgsqlConnection.Open blocked in Npgsql.ConnectorPool.Allocate() call to Monitor.Enter

.NET 5.6.1 Tasks Parallel Library - 基于应用程序在 NpSql.dll 3.1.6 调用 NpgsqlConnection.Open().[=15 时停止响应=]

经过进一步调查,似乎有 100 个为特定连接字符串提供服务的线程正在等待 Monitor.Enter 信号。等待线程的调用堆栈与此相同:

[GCFrame: 000000cd8922cec8] 
[GCFrame: 000000cd8922d0f0] 
[HelperMethodFrame: 000000cd8922d128] System.Threading.Monitor.Enter(System.Object)
Npgsql.ConnectorPool.Allocate(Npgsql.NpgsqlConnection, Npgsql.NpgsqlTimeout)
Npgsql.NpgsqlConnection.OpenInternal() 

锁转储指向孤立锁问题:MonitorHeld 值等于 1 个所有者 + 546 个等待者 (1+546*2=1093),锁所有者线程已死(线程为 0)

Index     SyncBlock      MonitorHeld    Owning  Thread    Info       Owner
220427  000000d26dd7b028   1093           1       0        XXX   Npgsql.ConnectorPool

ConnectorPool.Allocate() 中的不安全代码块内部没有生成异常,这有助于解释孤立锁。

没有理由相信 我们的 代码导致线程过早死亡:我们在应用程序的任何地方都没有明确调用 Thread.Abort( )

此时我们运行没主意了。 感谢您查看这个。

更新:

  1. 我们团队的一名成员 submitted 向 npsql 报告了错误。

  2. 在对我们的日志进行更彻底的搜索后,我们发现由于竞争条件,来自 NpSql dll 版本 3.1.6 中 ConnectorPool.Allocate() 的单个 NullReferenceException 实例。查看当前 NpSql 存储库中的 ConnectorPool.cs,此特定问题已通过将静态 _pruningTimer 转换为自版本 3.1.7 以来的基于实例的字段得到解决。

结论:从 NpSql 3.1.6 升级到 3.1.7 解决了 ConnectorPool.Allocate() 中的死锁。