0

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?

john93230
  • 243
  • 1
  • 2
  • 9
  • It could work to declare threadFinished as volatile but please google for a better singleton pattern instead. – fhogberg Jan 29 '16 at 19:48

3 Answers3

2

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.

Community
  • 1
  • 1
Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
  • Thanks for Your answer. But I need to start new Thread - and than run code on it's SynchornizationContext. So what is the best solution for start new backround thread only once? – john93230 Jan 29 '16 at 20:07
  • Why it has to be in another thread? I don't see the exact problem. Can you explain a bit? – Sriram Sakthivel Jan 29 '16 at 20:09
  • That new Thread execute WebCore.Run() from http://docs.awesomium.net/html/M_Awesomium_Core_WebCore_Run.htm So that thread is blocked as specified in doc. WebCore,Run() is blocking thread which on it is executed so I need to create new and run WebCore.Run() only once. After I get SynchronizationContext.Current it is used in Parallel loop – john93230 Jan 29 '16 at 20:12
  • You can start it in another thread. But don't wait for it. i.e just removing the `while (!threadFinished)` should work. Am I missing something? – Sriram Sakthivel Jan 29 '16 at 20:16
  • It doesn't because myContext (the new Thread set it from SynchronizationContext.Current) is null until WebCore is Initialized - it takes 1-2 sek. So I need to wait for WebCore Initilization. MyAction() contains `WebCore.Started += (s, e) => { myContext = SynchronizationContext.Current; };` After removing `while` myContext.Send() throws exception – john93230 Jan 29 '16 at 20:25
1

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;
    }
}
Aaron
  • 1,313
  • 16
  • 26
0

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

GuyVdN
  • 690
  • 4
  • 14