Лучший отвечающий
Потокобезопасность. Организация наилучшей записи/чтения данных.

Вопрос
-
Здравствуйте!
Хотелось бы найти оптимальный способ для потокобезопасности обращения к данным массива.
Насколько я понимаю - чтение данных из массива можно выполнять сразу из нескольких потоков, а вот запись только из одного. Каким образом можно построить блокировку, чтобы при чтении не блокировать остальные потоки на чтение?
Привожу кодclass Test
{ object lockObj = new object(); Dictionary<someT, someValue> m_dictionary = new Dictionary<someT, someValue>(); public someValue GetValue(someT) { lock (lockObj) {
// Поиск значения в m_dictionary ... } } public void AddValue(someT, someValue) { lock(lockObj) { // Добавление значения в m_dictionary ...
} }
}
В коде видно, что при попытке одновременного чтения из разных потоков - по сути чтение сможет выполнять только один поток, т.к. остальные будут заблокированы, даже в отсутствии операции на запись.
Как построить блокировку, чтобы не блокировать одновременное чтение из разных потоков в отсутствии записи, но в тоже время сохранить потокобезопасность?- Перемещено Siddharth Chavan 1 октября 2010 г. 22:43 MSDN Forums Consolidation (От:Visual C#)
11 января 2010 г. 8:15
Ответы
-
Извините, но меня не устраивают ответы - "может сработать, а может и нет"..
Именно поэтому я не пометил галочку - Предложить как ответ.
А теперь помечу
http://msdn.microsoft.com/ru-ru/library/system.threading.readerwriterlock.aspx11 января 2010 г. 10:36
Все ответы
-
class Test { object lockObj = new object(); Dictionary<someT, someValue> m_dictionary = new Dictionary<someT, someValue>(); public someValue GetValue(someT) { // Поиск значения в m_dictionary ... } public void AddValue(someT, someValue) { lock(lockObj) { // Добавление значения в m_dictionary ... } } }
11 января 2010 г. 8:28 -
А разве не нарушается потокобезопасность?
Предположим, что 10 потоков выполняют чтение из массива и в этот же момент происходит добавление нового элемента в массив.. Думаю, что скорее всего студия выбросит исключение..11 января 2010 г. 8:34 -
А разве не нарушается потокобезопасность?
Предположим, что 10 потоков выполняют чтение из массива и в этот же момент происходит добавление нового элемента в массив.. Думаю, что скорее всего студия выбросит исключение..
На операции записи у вас стоит блокировка, так что в момент записи доступ к коллеции имеет только один поток, тот что записывает. А чтение не влияет на коллекцию, разве что вы неверные данные можете прочесть если не блокируете операцию чтения. Например, поток начал чтение, приостановился, в этот элемент записалось новое значение, и вы продолжили чтение.11 января 2010 г. 8:44 -
А разве не нарушается потокобезопасность?
Предположим, что 10 потоков выполняют чтение из массива и в этот же момент происходит добавление нового элемента в массив.. Думаю, что скорее всего студия выбросит исключение..
На операции записи у вас стоит блокировка, так что в момент записи доступ к коллеции имеет только один поток, тот что записывает. А чтение не влияет на коллекцию, разве что вы неверные данные можете прочесть если не блокируете операцию чтения. Например, поток начал чтение, приостановился, в этот элемент записалось новое значение, и вы продолжили чтение.
По-моему как раз в момент записи, если не блокировать чтение, к колекции доступ на чтение имеют любые потоки в предложенном варианте кода.
Пусть в GetValue(someT) поочередно перебираются все элементы этой коллекции.. (например это занимает 10 секунд, коллекция очень большая)
Есть несколько потоков и в один прекрасный момент времени случится одновременный вызов, например:
Thread1->GetValue()
Thread2->GetValue()
Thread3->AddValue()
..
Если не блокировать операцию чтения, то получится, что во время выполнения GetValue() от Thread1 или Thread2 произойдет изменения коллекции и выпадет исключение. Я не прав?11 января 2010 г. 8:53 -
Да, только совсем необязательно исключение может выдать. Может всё сработает гладко, только с испорченными результатами.11 января 2010 г. 8:58
-
Извините, но меня не устраивают ответы - "может сработать, а может и нет"..
Хотелось бы получить оптимальный вариант блокировки - чтобы читать могли все потоки, а блокировка на чтение проводилась только в момент записи + с соблюдением потокобезопасности
Т.е. случаи:
- нет записи -> потоки, выполняющие чтение, свободно обращаются к массиву
- нужна запись -> чтение блокируется, выполняется запись, чтение разблокируется и опять осуществляется свободный доступ всех потоков на чтение, до следующей записи11 января 2010 г. 10:04 -
Извините, но меня не устраивают ответы - "может сработать, а может и нет"..
Именно поэтому я не пометил галочку - Предложить как ответ.
А теперь помечу
http://msdn.microsoft.com/ru-ru/library/system.threading.readerwriterlock.aspx11 января 2010 г. 10:36 -
А мож вот так?)
class Test { object lockObj = new object(); Dictionary<someT, someValue> m_dictionary = new Dictionary<someT, someValue>(); public someValue GetValue(someT) { lock (lockObj) { } // Поиск значения в m_dictionary ... } public void AddValue(someT, someValue) { lock(lockObj) { // Добавление значения в m_dictionary ... } } }
Хотя через ReaderWriterLock будет правильней :)
11 января 2010 г. 10:43 -
А мож вот так?)
class Test { object lockObj = new object(); Dictionary<someT, someValue> m_dictionary = new Dictionary<someT, someValue>(); public someValue GetValue(someT) { lock (lockObj) { } // Поиск значения в m_dictionary ... } public void AddValue(someT, someValue) { lock(lockObj) { // Добавление значения в m_dictionary ... } } }
Хотя через ReaderWriterLock будет правильней :)
Нет, это некоректно, т.к. если обратиться к методу AddValue в момент времени выполнения блока в методе GetValue "// Поиск значения в m_dictionary", то произойдет исключение.
---
OlegGel, огромное спасибо! Это действительно то что нужно, судя по описаниям с msdn. Буду разбираться..11 января 2010 г. 10:51 -
чет совсем затупил я)11 января 2010 г. 10:53