Вы могли описать два метода синхронизации многопоточного доступа для записи, выполненного на участнике класса?
Мог любой помогать мне, что, это означало делать и что является правильным ответом.
При изменении данных в C #, то, что выглядит как единая операция, может быть скомпилирована в несколько инструкций. Возьмите следующий класс:
public class Number {
private int a = 0;
public void Add(int b) {
a += b;
}
}
, когда вы построите его, вы получаете следующий код IL:
IL_0000: nop
IL_0001: ldarg.0
IL_0002: dup
// Pushes the value of the private variable 'a' onto the stack
IL_0003: ldfld int32 Simple.Number::a
// Pushes the value of the argument 'b' onto the stack
IL_0008: ldarg.1
// Adds the top two values of the stack together
IL_0009: add
// Sets 'a' to the value on top of the stack
IL_000a: stfld int32 Simple.Number::a
IL_000f: ret
Теперь, скажем, у вас есть объект
, и два потока вызова его Добавить
метод Как это:
number.Add(2); // Thread 1
number.Add(3); // Thread 2
Если вы хотите, чтобы результат был 5 (0 + 2 + 3), есть проблема. Вы не знаете, когда эти потоки будут выполнять свои инструкции. Обе нити могут выполняться IL_0003
(нажав ноль на стек) перед выполнением IL_000A
(фактически изменение переменной элемента), и вы получаете это:
a = 0 + 2; // Thread 1
a = 0 + 3; // Thread 2
Последняя поток для окончания победы «И в конце процесса
A
- 2 или 3 вместо 5.
, поэтому вы должны убедиться, что один полный набор инструкций заканчивается до другого набора. Для этого вы можете:
1) блокировать доступ к элементу класса, когда он написан, используя один из многих примитивов синхронизации .NET (вроде блокировки
, Mutex
, READERWRITERLOCKSSLIM
и т. Д.) Так что только один поток может работать на нем за раз.
2) Нажмите «Записать операции в очередь» и обрабатывайте эту очередь одним потоком. Когда торарин указывает, вы все еще должны синхронизировать доступ к очереди , если это не безопасно, но оно того стоит для сложных операций записи.
Есть и другие методы. Некоторые (вроде заблокированы
) ограничены определенными типами данных, и даже больше (например, те, которые обсуждаются в , не блокирующих синхронизацию , а часть 4 резьба Джозефа Альбахари в C # ), хотя они более сложны: подходите к ним с осторожностью.
Есть несколько способов, несколько из которых упоминаются ранее.
, пока я не буду Я хочу определить другие ответы, я бы не доверял ничего, что не использует одну из этих методов. Мои извинения, если я забыл.
В многопоточных приложениях существует множество ситуаций, когда одновременный доступ к той же данным может вызвать проблемы. В таких случаях синхронизация требуется, чтобы гарантировать, что только один нить имеет доступ в любое время.
Предлагаю, что они означают, что они имеют в виду использование блокировки
(или Synclock
в VB.NET) против с использованием монитора
.
Вы можете захотеть прочитать эту страницу для примеров и понимания концепции. Однако, если у вас нет опыта работы с многопотативным дизайном приложений, он, вероятно, будет быстро очевиден, должен ли ваш новый работодатель поместить вас в тест. Это довольно сложный предмет, со многими возможными подводными камнями, такими как тупик .
Существует приличный на странице MSDN на эту тему .
Могут быть другие варианты, в зависимости от типа переменных элементов и того, как его изменено. Увеличение целого числа, например, можно сделать с помощью метода . Методом .
В качестве управлений и демонстрация проблемы, попробуйте написать приложение, которое начинается 5 одновременных потоков, увеличивая общий счетчик в миллион раз на поток. Предназначенный конечный результат счетчика составит 5 миллионов, но это (вероятно) не то, что вы получите с :)
Редактировать: сделал быструю реализацию себя ( скачать ). Образец вывода:
Unsynchronized counter demo:
expected counter = 5000000
actual counter = 4901600
Time taken (ms) = 67
Synchronized counter demo:
expected counter = 5000000
actual counter = 5000000
Time taken (ms) = 287