Безопасен ли одноэтапный поток Structuremap? - PullRequest
3 голосов
/ 26 марта 2010

В настоящее время у меня есть следующий класс:

    public class PluginManager
{
    private static bool s_initialized;
    private static object s_lock = new object();

    public static void Initialize() {
        if (!s_initialized) {
            lock (s_lock) {
                if (!s_initialized) {
                    // initialize

                    s_initialized = true;
                }
            }
        }
    }
}

Здесь важно то, что Initialize () должен выполняться только один раз во время работы приложения. Я думал, что я реорганизовал бы это в одноэлементный класс, так как это было бы более потокобезопасным?:

    public sealed class PluginService
{
    static PluginService() { }
    private static PluginService _instance = new PluginService();
    public static PluginService Instance { get { return _instance; } }

    private bool s_initialized;

    public void Initialize() {
        if (!s_initialized)
        {
            // initialize

            s_initialized = true;
        }
    }
}

Вопрос первый, все-таки необходимо ли здесь иметь блокировку (я ее снял), поскольку мы будем когда-либо работать только над одним экземпляром?

Наконец, я хочу использовать DI и структурную карту для инициализации моих сервисов, поэтому я реорганизовал их следующим образом:

    public interface IPluginService {
    void Initialize();
}

public class NewPluginService : IPluginService
{
    private bool s_initialized;
    public void Initialize() {
        if (!s_initialized) {
            // initialize

            s_initialized = true;
        }
    }
}

И в моем реестре:

            ForRequestedType<IPluginService>()
            .TheDefaultIsConcreteType<NewPluginService>().AsSingletons();

Это работает как ожидалось (синглтон возвращает true в следующем коде):

            var instance1 = ObjectFactory.GetInstance<IPluginService>();           
        var instance2 = ObjectFactory.GetInstance<IPluginService>();

        bool singleton = (instance1 == instance2);

Итак, мой следующий вопрос, является ли решение для структурной карты таким же потокобезопасным, как класс singleton (второй пример). Единственным недостатком является то, что это все еще позволяет напрямую создавать экземпляр NewPluginService (если не используется структурная карта).

Большое спасибо, Бен

1 Ответ

3 голосов
/ 28 марта 2010

Я бы сделал несколько рекомендаций:

  • логический флаг должен быть volatile
  • сделай свой экземпляр синглтона readonly
  • инициализация не является поточно-ориентированной, независимо от того, что у вас есть только один экземпляр ... поэтому он должен быть синхронизирован

    public sealded class PluginService
    {
    
    static PluginService() { }
    
    //make the instance readonly
    private static readonly PluginService _instance = new PluginService();
    public static PluginService Instance { get { return _instance; } }
    
    // make the flag volatile
    private static volatile bool s_initialized = false;
    private static object s_lock = new object();
    
    
    // you still need to synchronize when you're initializing
    public void Initialize() {
        lock(s_lock)
        {
            if (!s_initialized)
            {
                // initialize
    
                    s_initialized = true;
                }
            }
        }
    }
    

На структурированной карте нет разногласий, поэтому ее безопасность потоков не кажется нарушенной ...

Класс синглтона, который вы имели, не был потокобезопасным. Главное, что нужно помнить, это то, что один экземпляр не обеспечивает доступ к нему только одному потоку. Если есть несколько потоков, которые имеют ссылку на экземпляр, то существует конфликт между экземпляром и данными, которые он содержит. Если есть конфликт, вы должны обеспечить безопасность потока (синхронизировать как минимум).

...