Singleton - 构造函数内部的任务无法启动/不会异步启动

时间:2017-01-17 12:10:19

标签: c# multithreading singleton task autoresetevent

我有一点奇怪的问题很难解释。我有单例类,在构造函数中我必须运行一个任务来初始化一些组件/资源。

我在深度中使用了来自 C#的单例实现2,在一种情况下,一切正常,在另一种情况下 - 不是。

下面提供了一些评论代码。 由于某种原因任务未在一种情况下启动,当我使用具有初始和静态构造函数的静态字段(类 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;
        }
    }
}

我很好奇为什么会发生这种情况以及如何在将来避免这些问题。非常感谢!

1 个答案:

答案 0 :(得分:2)

这种奇怪的'的根本原因。行为非常简单 - CLR在锁定下执行静态构造函数。这可以防止创建的线程输入TaskThread()方法并将startEvent设置为信号状态。

在你面对这样一个问题和困惑几个小时后,为什么会发生这种情况,你就会明白为什么许多消息来源建议不要使用可疑的结构,如静态构造函数,全局变量等。