Не могли бы вы описать два метода синхронизации многопоточного доступа на запись на члене класса?Интервью Вопрос о .NET Threading
Пожалуйста, может кто-нибудь помочь мне, что это значит, и что это правильный ответ.
Не могли бы вы описать два метода синхронизации многопоточного доступа на запись на члене класса?Интервью Вопрос о .NET Threading
Пожалуйста, может кто-нибудь помочь мне, что это значит, и что это правильный ответ.
При изменении данных на 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
так:
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 synchronization primitives (как lock
, Mutex
, ReaderWriterLockSlim
и т.д.), так что только один поток может работать на нем вовремя.
2) Переместите операции записи в очередь и обработайте эту очередь одним потоком. Как указывает Торарин, вам все равно придется синхронизировать доступ к очереди , если он не является потокобезопасным, но он стоит для сложных операций записи.
Существуют и другие методы. Некоторые (например, Interlocked
) ограничены конкретными типами данных, и есть еще больше (например, те, которые обсуждаются в Non-blocking synchronization и Part 4 of Joseph Albahari's Threading in C#), хотя они сложнее: используйте их с осторожностью.
В многопоточных приложениях существует много ситуаций, когда одновременный доступ к тем же данным может вызвать проблемы. В таких случаях требуется синхронизация, чтобы гарантировать, что только один поток имеет доступ в любой момент времени.
Я предполагаю, что они подразумевают использование lock
-statement (или SyncLock
в VB.NET) против использования Monitor
.
Возможно, вы найдете read this page для примеров и понимания концепции. Однако, если у вас нет опыта разработки многопоточных приложений, это, скорее всего, станет очевидным, если ваш новый работодатель проведет вас на тест. Это довольно сложный вопрос с множеством возможных ошибок, таких как deadlock.
Существует достойный MSDN page on the subject.
Могут быть другие варианты, в зависимости от типа переменной-члена и способа их изменения. Например, приращение целого числа можно выполнить с помощью метода Interlocked .Increment.
Как упражнение и демонстрация проблемы, попробуйте написать приложение, которое запускает 5 одновременных потоков, увеличивая общий счетчик миллион раз на поток. Предполагаемый конечный результат счетчика составит 5 миллионов, но это (возможно) не то, что вы в итоге получите :)
Редактировать: сделана быстрая реализация сама (download). Образец выходного сигнала:
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
Спасибо за ответ. Я хотел бы узнать больше о многопоточности в .NET (C#). Infact Мне нужно знать больше о C# вообще. Не могли бы вы предложить мне одну книгу, которая может превратить обычного разработчика в разработчика следующего поколения. – Supremestar
Никаких конкретных названий не приходит в голову, но я не очень много использую книги. На самом деле это довольно удивительно, что я предварительно заказал C# по глубине, второе издание. Хорошие вещи, но есть, вероятно, книги, более подходящие для ваших нужд. – Thorarin
«C# in Depth» - потрясающая книга. –
Существует несколько способов, некоторые из которых упомянуты ранее.
Хотя я не хочу отрицать другие ответы, я не буду доверять никому, что не использует один из этих методов. Приносим извинения, если я забуду.
+1 для ReadWriterLockSlim. Тем не менее, я думаю, что OP должен еще больше ознакомиться с многопоточным программированием, прежде чем полностью понять эту концепцию. Что касается вашего второго момента: вам нужно будет синхронизировать очередь, просто усложняя вашу проблему. – Thorarin
Достаточно, и ваш ответ дает гораздо более глубокое представление об этих концепциях (хотя я пытаюсь использовать другой подход в обновлении). О очереди, правда, тоже нужно синхронизировать, хотя бывают случаи, когда такой подход упрощает вещи, а не усложняет их! –