Generic singleton initialization template on background

I currently have one single, which can take up to 10 seconds to initialize. However, I do not want my users to punish (expect) this initialization, so I would prefer to load this component into the background thread during application startup. Here is what I have:

Singleton:

public class MySingleton { private static MySingleton _instance; private static readonly object _locker = new object(); private MySingleton() { Init(); } public static MySingleton Instance { if(_instance == null) _instance = new MySingleton(); return _instance; } public void Init() { lock(_locker) { if(_instance != null) return; // long running code here... } } } 

Application Launch:

 Task.Factory.StartNew(() => MySingleton.Instance.Init()); 

This code works, protects against double initialization, protects it from the boundary case of the user who needs it, before it is initialized, and also protects it from the fact that someone forgot to call Init ().

However, it feels a bit awkward for two reasons: a) I run the Init method twice at startup. b) I would like to make threads inside a singleton, but something should initiate initialization.

Is there a cleaner / better / better way to handle this?

Thanks in advance for your help.

** EDIT: As stated in the comments, Init was mistakenly restricted to private. It must be publicly available and fixed.

+6
source share
3 answers

Use the static constructor to run it and ManualResetEvent to synchronize. This gives you a solution where everything is done within the real class. Therefore, it does not depend on what someone should call your init method.

 public class MySingleton { private static MySingleton _instance; private static ManualResetEvent _initEvent = new ManualResetEvent(false); static MySingleton() { ThreadPool.QueueUserWorkItem(state => Init()); } public static MySingleton Instance { _initEvent.Wait(); return _instance; } private static void Init() { _instance = new MySingleton(); // long running code here... _initEvent.Set(); } } 

The event will remain a signal after being triggered, which means that the instance property will be returned as soon as possible when the Init method is executed.

+9
source

You must define and call the singleton class as shown below ...

  var instance = MySingleton.Instance; while (true) { /// check for whether singleton initialization complete or not if (MySingleton.Initialized) { break; } } public class MySingleton { private static MySingleton _instance; private static readonly object _locker = new object(); public static bool Initialized { get; set; } private MySingleton() { ThreadPool.QueueUserWorkItem(call => Init()); } public static MySingleton Instance { get { if (_instance == null) _instance = new MySingleton(); return _instance; } } private void Init() { lock (_locker) { if (Initialized) return; // long running code here... for (int i = 0; i < 10000; i++) { } Initialized = true; } } } 
0
source

I would go with Task<T> :

 class Program { static void Main(string[] args) { MySingleton.Init(); Thread.Sleep(7000); Console.WriteLine("Getting instance..."); var mySingleton = MySingleton.Instance; Console.WriteLine("Got instance."); } public class MySingleton { private static Lazy<MySingleton> instance; public static MySingleton Instance { get { return instance.Value; } } public static void Init() { var initTask = Task.Factory.StartNew(() => { for(int i = 0; i < 10; i++) { Thread.Sleep(1000); Console.WriteLine("Doint init stuff {0}...", i); } return new MySingleton(); }); instance = new Lazy<MySingleton>(() => initTask.Result); } private MySingleton() { } } } 
0
source

Source: https://habr.com/ru/post/911831/


All Articles