单例 - 构造函数中的任务无法启动/无法异步启动
Singleton - task inside constructor fails to start/ does not start asynchronically
我有一个难以解释的奇怪问题。我有单例 class,在构造函数中我必须 运行 一个任务来初始化一些 components/resources。
我使用了 C# in Depth 中的 2 个单例实现,在一种情况下一切正常,在另一种情况下 - 不是。
下面提供了代码和一些注释。
由于某种原因,在一种情况下任务没有启动的主要问题是,当我使用带有初始值和静态构造函数的静态字段时(class Test2)。
我做了一些其他测试,看起来 实现 2 任务不会异步启动,而是在等待时间后同步启动。
实施一。一切都按预期工作
public sealed class Test1
{
private static Test1 instance = null;
private static readonly object padlock = new object();
private Test1()
{
using (AutoResetEvent startEvent = new AutoResetEvent(false))
{
new Task(() => TaskThread(startEvent)).Start();
if (!startEvent.WaitOne(1000))
{
throw new Exception("ERROR");
}
}
}
public int Result()
{
return 10;
}
private void TaskThread(AutoResetEvent startEvent)
{
//I am initializing some stuff here
startEvent.Set();
}
public static Test1 Instance
{
get
{
lock (padlock)
{
if (instance == null)
{
instance = new Test1();
}
return instance;
}
}
}
}
实现2,任务从不启动,或者在事件等待时间后启动
public sealed class Test2
{
private static readonly Test2 instance = new Test2();
static Test2()
{
}
private Test2()
{
using (AutoResetEvent startEvent = new AutoResetEvent(false))
{
new Task(() => TaskThread(startEvent)).Start();
//here it fails to wait successfully and throws an
//exception. Time limit is not reached
if (!startEvent.WaitOne(1000))
{
throw new Exception("ERROR");
}
}
}
public int Result()
{
return 20;
}
private void TaskThread(AutoResetEvent startEvent)
{
//I am initializing some stuff here as well
//but in this implementation code is never reached
startEvent.Set();
}
public static Test2 Instance
{
get
{
return instance;
}
}
}
我很好奇为什么会发生这种情况以及将来如何避免这种问题。非常感谢!
这种 'strange' 行为的根本原因非常简单 - CLR 在锁定的情况下执行静态构造函数。这可以防止创建的线程进入 TaskThread()
方法并将 startEvent
设置为信号状态。
在你面对这样的问题并困惑几个小时为什么会这样之后,你开始理解为什么许多消息来源建议不要使用可疑的构造,如静态构造函数、全局变量等。
我有一个难以解释的奇怪问题。我有单例 class,在构造函数中我必须 运行 一个任务来初始化一些 components/resources。
我使用了 C# in Depth 中的 2 个单例实现,在一种情况下一切正常,在另一种情况下 - 不是。
下面提供了代码和一些注释。 由于某种原因,在一种情况下任务没有启动的主要问题是,当我使用带有初始值和静态构造函数的静态字段时(class Test2)。
我做了一些其他测试,看起来 实现 2 任务不会异步启动,而是在等待时间后同步启动。
实施一。一切都按预期工作
public sealed class Test1
{
private static Test1 instance = null;
private static readonly object padlock = new object();
private Test1()
{
using (AutoResetEvent startEvent = new AutoResetEvent(false))
{
new Task(() => TaskThread(startEvent)).Start();
if (!startEvent.WaitOne(1000))
{
throw new Exception("ERROR");
}
}
}
public int Result()
{
return 10;
}
private void TaskThread(AutoResetEvent startEvent)
{
//I am initializing some stuff here
startEvent.Set();
}
public static Test1 Instance
{
get
{
lock (padlock)
{
if (instance == null)
{
instance = new Test1();
}
return instance;
}
}
}
}
实现2,任务从不启动,或者在事件等待时间后启动
public sealed class Test2
{
private static readonly Test2 instance = new Test2();
static Test2()
{
}
private Test2()
{
using (AutoResetEvent startEvent = new AutoResetEvent(false))
{
new Task(() => TaskThread(startEvent)).Start();
//here it fails to wait successfully and throws an
//exception. Time limit is not reached
if (!startEvent.WaitOne(1000))
{
throw new Exception("ERROR");
}
}
}
public int Result()
{
return 20;
}
private void TaskThread(AutoResetEvent startEvent)
{
//I am initializing some stuff here as well
//but in this implementation code is never reached
startEvent.Set();
}
public static Test2 Instance
{
get
{
return instance;
}
}
}
我很好奇为什么会发生这种情况以及将来如何避免这种问题。非常感谢!
这种 'strange' 行为的根本原因非常简单 - CLR 在锁定的情况下执行静态构造函数。这可以防止创建的线程进入 TaskThread()
方法并将 startEvent
设置为信号状态。
在你面对这样的问题并困惑几个小时为什么会这样之后,你开始理解为什么许多消息来源建议不要使用可疑的构造,如静态构造函数、全局变量等。