Является ли замена этой ссылки в первую очередь безопасной в многопоточной среде?
Извините, что wishy-washy здесь, но это зависит от того, как вы определяете"safe".
- Это безопасно, поскольку не повредит состояние.Это связано с тем, что эталонные назначения являются атомарными.
- Это не безопасно в том смысле, что это может привести к непреднамеренному поведению.
Непреднамеренное поведение можно разделить на триширокие категории.
- Комбинация чтения с последующей записью может привести к состоянию гонки.
- Один поток может не наблюдать изменения, внесенные другим из-за оптимизации компилятора и аппаратного обеспечения.
- В одном потоке может наблюдаться изменение между двумя различными чтениями ссылочной переменной.
Случай № 1: Таким образом, в первом случае два потока могут переходить ксделать назначение под ложными предлогами.Лучший пример этого - создание синглтона.
public static Singleton GetSingleton()
{
// More than one thread could read null and attempt instantiation here.
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
Случай № 2: Во втором случае один поток может продолжать читать старый экземпляр, даже если новый экземпляр былопубликовано в другой ветке.Рассмотрим этот пример.
public class Example
{
private SuperHero hero = new Superman();
void ThreadA()
{
while (true)
{
Thread.Sleep(1000);
hero = new CaptainAmerica();
Thread.Sleep(1000);
hero = new GreenLantern();
Thread.Sleep(1000);
hero = new IronMan();
}
void ThreadB()
{
while (true)
{
hero.FightTheBadGuys();
}
}
}
Проблема в том, что компилятор или аппаратное обеспечение может оптимизировать ThreadB
, "подняв" чтение значения hero
вне цикла, как это.
void ThreadB()
{
SuperHero local = hero;
while (true)
{
local.FightTheBadGuys();
}
}
Не должно быть трудно видеть, что один из наших супергероев очень сильно устанет.Опять же, он супергерой , так что, в конце концов, проблем не будет.Я пытаюсь подчеркнуть, что этот устаревший артефакт может быть или не быть проблемой в зависимости от вашей ситуации.
Случай № 3: В третьемЕсли поток может ошибочно предположить, что переменная будет ссылаться на один и тот же экземпляр между двумя операциями чтения.
void SomeThread()
{
var result1 = instance.DoSomething();
// The variable instance could get changed here!
var result2 = instance.DoSomethingElse();
// Are result1 and result2 in a mutually consistent state here?
}
В приведенном выше примере result1
и result2
могут не находиться во взаимно согласованном состоянии.Это потому, что они были получены из операций, выполняющихся в двух разных экземплярах.Опять же, это может или не может быть проблемой в зависимости от вашего конкретного сценария.