C# singleton中的新线程从未完成

C# singleton中的新线程从未完成,c#,multithreading,C#,Multithreading,我有一个简单的单身班: namespace TestApp { public class MySingleton { static MySingleton() { } private static readonly MySingleton instance = new MySingleton(); private bool threadFinished = false; publi

我有一个简单的单身班:

namespace TestApp
{
    public class MySingleton
    {
        static MySingleton()
        {
        }

        private static readonly MySingleton instance = new MySingleton();
        private  bool threadFinished = false;
        public bool IsReady = false;

        private MySingleton()
        {
            Thread t = new Thread(MyAction);
            t.Start();

            while (!threadFinished)
               Thread.Sleep(10);
        }

        public static MySingleton Instance
        {
            get { return instance; }
        }

        private void MyAction()
        {
            threadFinished = true;
        }
    }
}
当我试图通过以下方式来稳定此过程:

var ir =  MySingleton.Instance.IsReady;

它永远不会结束——while循环是无限的。为什么?以及如何在构造函数的singleton中运行反向线程?

您处于死锁状态。在执行静态构造函数之前,不允许从其他线程调用任何方法。静态构造函数也包括静态字段初始化器

由于使用while循环阻塞调用线程,静态字段初始化将不会完成,新线程也不允许执行
MyAction

您的代码与Eric演示死锁的代码几乎相同

引用eric对同一答案的评论,为什么会死锁:

@Lieven:静态构造函数必须运行不超过一次,并且 必须在第一次调用类中的任何静态方法之前运行。主要 是一个静态方法,因此主线程调用静态构造函数。到 确保它只运行一次,CLR将取出一个不可用的锁 释放,直到静态操作完成。当ctor启动一个新的 线程,该线程还调用静态方法,因此CLR尝试 获取锁以查看是否需要运行ctor。主线 同时“加入”被阻塞的线程,现在我们有了死锁 Eric Lippert 2012年1月17日14:28


回答你的问题;不要那样做。通过启动线程并等待它,您将一无所获。只需同步运行该方法。

您处于死锁状态。在执行静态构造函数之前,不允许从其他线程调用任何方法。静态构造函数也包括静态字段初始化器

由于使用while循环阻塞调用线程,静态字段初始化将不会完成,新线程也不允许执行
MyAction

您的代码与Eric演示死锁的代码几乎相同

引用eric对同一答案的评论,为什么会死锁:

@Lieven:静态构造函数必须运行不超过一次,并且 必须在第一次调用类中的任何静态方法之前运行。主要 是一个静态方法,因此主线程调用静态构造函数。到 确保它只运行一次,CLR将取出一个不可用的锁 释放,直到静态操作完成。当ctor启动一个新的 线程,该线程还调用静态方法,因此CLR尝试 获取锁以查看是否需要运行ctor。主线 同时“加入”被阻塞的线程,现在我们有了死锁 Eric Lippert 2012年1月17日14:28

回答你的问题;不要那样做。通过启动线程并等待它,您将一无所获。只需同步运行该方法。

在创建singleton实例以使其线程安全时,请查看

在这里可以找到如何在singleton模式中使用它的示例:

当您创建singleton实例以使其线程安全时,请查看


在这里可以找到如何在单例模式中使用它的示例:

这很有效。我不是单身专家——如果这违反了任何规则,请有人指出。但这可以打破僵局。我将您的代码复制到一个控制台应用程序中,如果您在其他地方使用它,请进行适当调整

namespace TestApp
{
class Program
{
    static void Main(string[] args)
    {
        while (!MySingleton.Instance.IsReady)
            Thread.Sleep(100);
        Console.WriteLine("Done");
        Console.Read();
    }
}

public class MySingleton
{
    static MySingleton()
    {
    }

    private static readonly MySingleton instance = new MySingleton();
    private static bool threadFinished = false;
    public bool IsReady
    {
        get { return threadFinished; }       
    }

    private MySingleton()
    {
        Thread t = new Thread(new ThreadStart(MyAction));

        t.Start();
    }

    public static MySingleton Instance
    {
        get { return instance; }
    }
    static void MyAction()
    {
        threadFinished = true;
    }
}

这很有效。我不是单身专家——如果这违反了任何规则,请有人指出。但这可以打破僵局。我将您的代码复制到一个控制台应用程序中,如果您在其他地方使用它,请进行适当调整

namespace TestApp
{
class Program
{
    static void Main(string[] args)
    {
        while (!MySingleton.Instance.IsReady)
            Thread.Sleep(100);
        Console.WriteLine("Done");
        Console.Read();
    }
}

public class MySingleton
{
    static MySingleton()
    {
    }

    private static readonly MySingleton instance = new MySingleton();
    private static bool threadFinished = false;
    public bool IsReady
    {
        get { return threadFinished; }       
    }

    private MySingleton()
    {
        Thread t = new Thread(new ThreadStart(MyAction));

        t.Start();
    }

    public static MySingleton Instance
    {
        get { return instance; }
    }
    static void MyAction()
    {
        threadFinished = true;
    }
}

可以将threadFinished声明为volatile,但请使用谷歌搜索更好的单例模式。可以将threadFinished声明为volatile,但请使用谷歌搜索更好的单例模式。谢谢您的回答。但我需要启动新的线程,然后在它的SynchornizationContext上运行代码。那么,对于只启动一次新的反向线程,什么是最好的解决方案呢?为什么它必须在另一个线程中?我看不出确切的问题。你能解释一下吗?这个新线程从执行WebCore.Run(),这样线程就按照文档中的指定被阻塞了。WebCore,Run()正在阻塞线程,该线程在其上执行,因此我需要创建新线程并只运行WebCore.Run()一次。在我获得SynchronizationContext.Current后,它将在并行循环中使用,您可以在另一个线程中启动它。但不要等待。i、 e只要在(!threadFinished)时删除
,就可以了。我遗漏了什么吗?这不是因为myContext(从SynchronizationContext.Current设置它的新线程)在WebCore初始化之前是空的-需要1-2 sek。所以我需要等待WebCore初始化。MyAction()包含
WebCore.Started+=(s,e)=>{myContext=SynchronizationContext.Current;}在删除
之后,而
myContext.Send()会抛出例外提示以获取您的答案。但我需要启动新的线程,然后在它的SynchornizationContext上运行代码。那么,对于只启动一次新的反向线程,什么是最好的解决方案呢?为什么它必须在另一个线程中?我看不出确切的问题。你能解释一下吗?这个新线程从执行WebCore.Run(),这样线程就按照文档中的指定被阻塞了。WebCore,Run()正在阻塞线程,该线程在其上执行,因此我需要创建新线程并只运行WebCore.Run()一次。在我获得SynchronizationContext.Current后,它将在并行循环中使用,您可以在另一个线程中启动它。但不要等待。i、 e只要在(!threadFinished)
时删除
,就可以了。我遗漏了什么吗?这不是因为myContext(从SynchronizationContext.Current设置它的新线程)在WebCore初始化之前是空的-需要1-2 sek。所以我需要等待WebCore初始化。MyAction()包含
WebCore.Started+=(s,e)=>{myContext=SynchronizationContext.Current;}之后