C# Plinq语句在静态构造函数中陷入僵局
我遇到这样的情况,静态构造函数中的以下plinq语句陷入僵局:C# Plinq语句在静态构造函数中陷入僵局,c#,.net,task-parallel-library,plinq,C#,.net,Task Parallel Library,Plinq,我遇到这样的情况,静态构造函数中的以下plinq语句陷入僵局: static void Main(string[] args) { new Blah(); } class Blah { static Blah() { Enumerable.Range(1, 10000) .AsParallel() .Select(n => n * 3) .ToList(); }
static void Main(string[] args)
{
new Blah();
}
class Blah
{
static Blah()
{
Enumerable.Range(1, 10000)
.AsParallel()
.Select(n => n * 3)
.ToList();
}
}
它仅在构造函数是静态的情况下发生。
有人能给我解释一下吗
是第三方物流错误吗?编译程序?Me?不管它值多少钱,Mono上不会出现这个问题:
[mono] /tmp @ dmcs par.cs
[mono] /tmp @ mono ./par.exe
您是否有windows编译的二进制文件,以便我可以比较生成的MSIL?我不相信这是一个图书馆唯一的问题,我很好奇:)
比较IL有点混乱,所以我决定在两种平台上都试用这两种二进制文件。 呵呵,我恢复了我的旧Windows虚拟机只是为了测试这个:) 在Mono上运行VS编译的二进制文件没有问题。您可以使用2.10.1在windows上试用它(http://www.go-mono.com/mono-downloads/download.html),只有77.4Mb:) (我在linux上使用了定制的mono 2.11,因此功能支持可能还没有完成) 我还注意到,在windows上运行时,CTRL-C可以打破锁定。 如果我找到更多的话,我会发帖的
更新2 好吧,安装Mono会绕着在windows上安装VSExpress转一圈。安装mono在4分钟内完成,结果是:
C:\Users\Seth>"c:\Program Files (x86)\Mono-2.10.1\bin\mono.exe" ConsoleApplication2.exe
C:\Users\Seth>
没有死锁:)现在剩下的就是等待VSExpress安装(永远)和所有调试工具(未知),然后破解它(可能直到深夜)。CU稍后从静态构造函数调用线程代码通常是危险的。为了确保静态构造函数只执行一次,CLR在锁下执行静态构造函数。如果运行静态构造函数的线程等待助手线程,那么助手线程也有可能出于某种原因需要CLR内部锁,并且程序将死锁 下面是一个简单的代码示例,演示了该问题:
using System.Threading;
class Blah
{
static void Main() { /* Won’t run because the static constructor deadlocks. */ }
static Blah()
{
Thread thread = new Thread(ThreadBody);
thread.Start();
thread.Join();
}
static void ThreadBody() { }
}
第10.5.3.3节“竞争和死锁”保证以下内容:
除非某些代码
从类型初始值设定项(直接或间接)显式调用
调用阻塞操作
因此,类型初始值设定项(即静态构造函数)不会死锁,前提是静态构造函数中的任何操作都不会阻塞线程。如果静态构造函数真的阻塞了,它就有死锁的风险。虽然已经解释了为什么您不想在静态构造函数中执行线程工作,但我想我应该补充一点,这样做的“正确”方法是使用静态构造函数。这也更有效,因为在实际需要这些资源之前,生成这些资源的工作将被取消
class Blah
{
// Supply factory method to generate the numbers, but actual generation will be deferred
private static Lazy<List<int>> MyMagicNumbers = new Lazy<List<int>>(Blah.GenerateMagicNumbers);
public void DoSomethingWithMagicNumbers()
{
// Call to Lazy<T>.Value will synchronize any calling threads until value is initially generated from the factory
List<int> magicNumbers = Blah.MyMagicNumbers.Value;
// ... do something here ...
}
private List<int> GenerateMagicNumbers()
{
return Enumerable.Range(1, 10000)
.AsParallel()
.Select(n => n * 3)
.ToList();
}
}
class废话
{
//提供工厂方法生成数字,但实际生成将延迟
私有静态惰性MyMagicNumbers=新惰性(Blah.GenerateMagicNumbers);
公共无效DoSomethingWithMagicNumber()
{
//对Lazy.Value的调用将同步所有调用线程,直到最初从工厂生成值为止
List magicNumbers=Blah.MyMagicNumbers.Value;
//…在这里做点什么。。。
}
私有列表生成器magicnumbers()
{
返回可枚举范围(11000)
.天冬酰胺()
.选择(n=>n*3)
.ToList();
}
}
您是否有windows编译的二进制文件,以便我可以比较生成的MSIL?我不相信这是一个图书馆唯一的问题,我很好奇:)你可以从这里下载代码和二进制文件:这里是一个windows二进制文件:我暂时放弃。无法在全新(从不运行:)Win7_64虚拟机上运行VSExpress。安装service pack失败(?!),因此,唉,今天我没有注意到WinDbg。感谢您的辛勤工作。这似乎是TPLForWindows实现中的一个错误。如果死锁是一种预期行为,我想知道为什么它不会在mono中发生。他们不是锁定了静态构造函数吗?这是一个很好的观点。谢谢你的回答。这只是一些不直观的东西。至少如果它以某种方式抛出了异常。。。
class Blah
{
// Supply factory method to generate the numbers, but actual generation will be deferred
private static Lazy<List<int>> MyMagicNumbers = new Lazy<List<int>>(Blah.GenerateMagicNumbers);
public void DoSomethingWithMagicNumbers()
{
// Call to Lazy<T>.Value will synchronize any calling threads until value is initially generated from the factory
List<int> magicNumbers = Blah.MyMagicNumbers.Value;
// ... do something here ...
}
private List<int> GenerateMagicNumbers()
{
return Enumerable.Range(1, 10000)
.AsParallel()
.Select(n => n * 3)
.ToList();
}
}