Может ли быть упреждающий конструктор?

Возможно ли, чтобы конструктор был предварительно выпущен в С#?

Например, рассмотрим код:

public class A
{
    public bool ready = true;

    public A()
    {
        ready = false; // Point #1
        // Other initialization stuff
        ready = true; // Point #2
    }
}

Где-то еще в коде два потока имеют доступ к переменной типа A, первый поток вызывает конструктор, который предварительно упущен в точке # 1. Затем второй поток проверяет на ready и считает, что он по-прежнему прав, поэтому он делает что-то плохое.

Возможно ли это?

Более конкретно:

  • Может ли быть упреждающий конструктор?
  • Если да, значит ли это, что в конструкторе должен быть код синхронизации, например lock?
  • Создается ли объект только для общей переменной после выхода из конструктора, тем самым избегая вопроса вообще?

Ответ 1

Я не думаю, что принятый ответ правильный. Игорь Островский " Модель памяти С# в теории и практике" ( часть 2 здесь) подробно объясняет проблемы, и один из примеров иллюстрирует то, о чем вы просите.

Он дает код

class BoxedInt2
{
  public readonly int _value = 42;
  void PrintValue()
  {
    Console.WriteLine(_value);
  }
}

class Tester
{
  BoxedInt2 _box = null;
  public void Set() {
    _box = new BoxedInt2();
  }
  public void Print() {
    var b = _box;
    if (b != null) b.PrintValue();
  }
}

и примечания:

Поскольку экземпляр BoxedInt был неправильно опубликован (через поле энергонезависимости, _box), поток, который вызывает Print, может наблюдать частично сконструированный объект! Опять же, изменение поля в поле "_box" устранит проблему.

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

Ответ 2

Создается ли объект только для общей переменной после выхода конструктора, тем самым избегая вопроса вообще?

Да. Когда вы строите объект только тогда, когда конструктор возвращается, значение переменной присваивается переменной. Поэтому только после этого другой поток сможет вызвать, чтобы проверить, есть ли значение true или false.

Два потока не могут входить в конструктор одновременно.

Безопасные публикации - публикация не полностью созданного объекта

Но вы можете легко совершить ошибку, если публикуете ссылку на какой-либо общий список. Постарайтесь не делать что-то подобное в своем конструкторе

A(List sharedList){
    sharedList.add(this);

    //initializing instance variables
}

Pardon для Java-кода. Таким образом, в этом случае вы публикуете неполный созданный объект в общий список, к которому можно обратиться другим потоком и может привести к возникновению многих проблем.

Не публикуйте ссылку "this" во время построения, Java. Не знаю, конечно, если это относится к С#

Затем это возвращает меня к исходному вопросу, в С# можно конструктор будет предварительно упущен?

Что касается предпосылки, то IMO поток может быть прерван при запуске конструктора. Конструктор - это как обычный метод, но со специальной семантикой.

Это никоим образом не влияет на безопасность потока кода, так как только один поток может находиться внутри конструктора объекта. Таким образом, это абсолютно безопасный поток, пока вы не избежите неполностью построенной ссылки this.

Если да, значит ли это, что должен быть код синхронизации такой как блокировка в конструкторе?

Внутри конструктора не может находиться только один поток, поэтому он не зависит от потоков.