этот поток кода безопасен? - PullRequest
2 голосов
/ 10 августа 2011

Я хотел бы знать, является ли этот код потокобезопасным и почему, если это не так.

    static IMyInterface _myinterface;
        public static IMyInterface someStuff
        {
            get
            {
                if (_myinterface== null)
                {
                    _myinterface= MyServiceLocator.GetCurrent().GetInstance<IMyInterface>();
                }

                return _myinterface;
            }
        }

Спасибо!

Ответы [ 7 ]

4 голосов
/ 10 августа 2011

Как уже говорили другие, это не так. Тем не менее, есть довольно много опций, чтобы сделать его безопасным для потоков, кроме простого блокирования или шаблона с двойной проверкой, что не гарантирует работу на всех (возможных) реализациях CLR.

Также обратите внимание, что если вы не ожидаете высокой конкуренции, блокировка с двойной проверкой действительно не требуется и вряд ли будет иметь значение. Относительно легко ошибиться (см. Пример другой (изначально) неправильной реализации в одном из ответов).

См. статью Джона Скита на эту тему для получения дополнительной информации.

1 голос
/ 10 августа 2011

Это не потому, что может быть несколько потоков инициализации, которые будут пытаться получить доступ к синглтону одновременно.

Это может сработать:

    static object _lock=new object(); 
    static IMyInterface _myinterface;
    public static IMyInterface someStuff
    {
        get
        {
            lock (_lock) {
                if (_myinterface== null)
                {
                    _myinterface= MyServiceLocator.GetCurrent().GetInstance<IMyInterface>();
                }
            }
            return _myinterface;
        }
    }
1 голос
/ 10 августа 2011

Нет, это не так, вы хотите сделать что-то подобное.Обратите внимание на двойную проверку на _myinterface==null.Это связано с тем, что после вашей первой проверки другой поток уже может быть в блокировке, создающей его.Поэтому вам нужно перепроверить, как только вы доберетесь до замка.

static IMyInterface _myinterface;
private static object lockObj = new object();
public static IMyInterface someStuff
{
   get
   {
      if (_myinterface== null)
      {
         lock(lockObj)
         {
            if (_myinterface== null)
            {             
                _myinterface= MyServiceLocator.GetCurrent().GetInstance<IMyInterface>();
            }
         }
      }
      return _myinterface;
}
1 голос
/ 10 августа 2011

Нет.Вам нужно использовать замок.

private static readonly object m_lock = new object();
private static IMyInterface _myinterface;

public static IMyInterface someStuff
{
    get
    {
        lock(m_lock)
        {
           if (_myinterface == null)
           {
             //create instance
           }

           return _myinterface;
        }            
    }
}
1 голос
/ 10 августа 2011

Для меня это не так. Потому что между единственным способом быть уверенным это добавить блокировку на него. Возможно, в операторе if могут быть два потока!

http://msdn.microsoft.com/en-us/library/c5kehkcz%28v=vs.80%29.aspx

0 голосов
/ 10 августа 2011

Нет, может случиться, что два разных потока создают разные экземпляры и записывают предыдущее сохраненное значение _ myInterface.

Только представьте, что тема №1 вошла в if блок

if (_myinterface== null)                 
{
 // ... here

и Thread # 2 также читают _ myinterface и также входят в этот блок, в этот раз объект экземпляра Thread # 1 и обновленная ссылка _myinterface. Но в то же время Thread # 2 уже кэшировал значение _myinterface (это NULL) и создает новый объект и значение owerwriting, которое было сохранено в Thread # 1.

Обернуть геттер блокировкой (), чтобы в него мог войти только один поток (см. Другой ответ по поводу двойной блокировки)

0 голосов
/ 10 августа 2011

Нет, это не так.

Почему?

Два вызова поступают на someStuff, один проходит if(_myInterface null), но прерывается _myInterface = MYServiceLoc....Второй поток get полностью завершен и завершается перед сном.Второй активируется, присваивает _myInterface.

В итоге оба вызывают MyServiceLocator ... GetInstance (), оба присваивают _myInterface, и оба могут возвращать разные значения для _myInterface.

...