Является ли «шаблон взаимосвязанного чего-либо» из CLR через C# не потокобезопасным?C#

Место общения программистов C#
Ответить
Anonymous
 Является ли «шаблон взаимосвязанного чего-либо» из CLR через C# не потокобезопасным?

Сообщение Anonymous »

Читая о шаблоне Interlocked Anything, придуманном Джеффри Рихтером в CLR через C# 4-е издание, он приводит следующий пример, демонстрирующий, что мы можем сделать больше, чем просто добавить для Interlocked

Хотя класс Interlocked не предлагает этих методов, существует
хорошо известный шаблон, позволяющий выполнять любую операцию над
Int32 в < strong>атомарным способом с помощью Interlocked.CompareExchange.

Код: Выделить всё

public static Int32 Maximum(ref Int32 target, Int32 value)
{
Int32 currentVal = target, startVal, desiredVal;

// Don't access target in the loop except in an attempt
// to change it because another thread may be touching it
do
{
// Record this iteration's starting value
startVal = currentVal;

// Calculate the desired value in terms of startVal and value
desiredVal = Math.Max(startVal, value);

// NOTE: the thread could be preempted here!

// if (target == startVal) target = desiredVal
// Value prior to potential change is returned
currentVal = Interlocked.CompareExchange(ref target, desiredVal, startVal);

// If the starting value changed during this iteration, repeat
} while (startVal != currentVal);

// Return the maximum value when this thread tried to set it
return desiredVal;
}
Очень похожая версия шаблона можно найти для методов add и удаления, сгенерированных компилятором C# для событий:

Код: Выделить всё

[CompilerGenerated]
{
EventHandler eventHandler = this.MyEvent;
EventHandler eventHandler2;
do
{
eventHandler2 = eventHandler;
EventHandler value2 = (EventHandler)Delegate.Combine(eventHandler2, value);
eventHandler = Interlocked.CompareExchange(ref this.MyEvent, value2, eventHandler2);
}
while ((object)eventHandler != eventHandler2);
}
Однако одно большое различие заключается в том, как мы получаем «целевое» значение: аргумент ref вместо доступа к полю.
Исходный пример с использованием ref аргумент, что нужно сделать, чтобы предотвратить изменение целевого значения до того, как оно будет присвоено значению temp через:

Код: Выделить всё

Int32 currentVal = target, startVal, desiredVal;
Например, другой поток меняет значение так же, как мы переходим к началу метода?
РЕДАКТИРОВАТЬ: Вот пример того, что я среднее значение (стиль LINQPad)

Код: Выделить всё

void Main() {
var current = 33;
var otherThread = new Thread(() => MutateLocal(ref current));
otherThread.Start();
var result = Maximum(ref current, 55); // at this point current is 33

current.Dump(); // 100
result.Dump(); // 100
}

public static void MutateLocal(ref int target) {
Thread.Sleep(100);
target = 100;
}

public static Int32 Maximum(ref Int32 target, Int32 value) {
Console.WriteLine(target);
Thread.Sleep(200);
Console.WriteLine(target);

Int32 currentVal = target; // this is atomic...
// ... rest of the Maximum method from above
Таким образом, Max не выглядит очень атомарным, когда результат Maximum(ref 33, 55) равен 100, что является заявленной целью шаблона.

Подробнее здесь: https://stackoverflow.com/questions/785 ... threadsafe
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»