简体   繁体   中英

New thread in singleton never finished

I have simple singleton class:

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;
        }
    }
}

When I'm trying instatiate this by:

var ir =  MySingleton.Instance.IsReady;

it never ends - the while loop is infinite. Why? And how to run backround thread in singleton at constructor?

You're deadlocking. You're not allowed to call any methods from another thread before the static constructor is executed. Static constructor includes the static field initalizers too.

Since you're blocking the calling thread with a while loop, static field initialization will not complete and the new thread will neither be permitted to execute MyAction either.

Your code is almost identical to this code where Eric demonstrates the deadlock.

And to quote eric's comment from same answer why does it deadlock:

@Lieven: The static constructor must run no more than once and it must run before the first call to any static method in the class. Main is a static method, so the main thread calls the static ctor. To ensure it only runs once, the CLR takes out a lock that is not released until the static ctor finishes. When the ctor starts a new thread, that thread also calls a static method, so the CLR tries to take the lock to see if it needs to run the ctor. The main thread meanwhile "joins" the blocked thread, and now we have our deadlock. – Eric Lippert Jan 17 '12 at 14:28

To answer your question; Don't do that. You gain nothing by starting a thread and waiting for it. Just simply run the method synchronously.

This works. I am not a Singleton expert - if this violates any rules, someone please point it out. But this gets around the deadlock. I copied your code into a console app, if you're using it elsewhere, adjust appropriately.

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;
    }
}

Have a look at the lock statement when you create an instance of your singleton to make it thread safe.

An example of how to use it in the singleton pattern can be found here: http://www.dofactory.com/net/singleton-design-pattern

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM