Синхронизация в общей структуре данных - PullRequest
1 голос
/ 21 марта 2009

Рассмотрим код, который включает в себя запись нескольких потоков в общую структуру данных. Теперь каждый из этих потоков записывает объекты в общий контейнер, которые по сути уникальны. Возьмите следующий (вымышленный) пример:

class Logger
{
   IDictionary<string, Log> logDictionary = new Dictionary<string, Log>();

   // Method called by several other threads
   void AddLog(Log log)
   {
      logDictionary[log.ID] = log;
   }

   // Method called by a separate thread
   IList GetLog(/*some criteria*/)
   {
      // loop through logDictionary and
      // create an IList based on criteria
   }
}

Я ясно понимаю, что одновременный доступ к общему объекту может быть проблемой, если несколько потоков пытаются обновить одну и ту же «переменную» (или слот), что приводит к условиям гонки. Теперь мой вопрос состоит из 3 частей.

(1) Необходима ли синхронизация, если потоки делают слепые обновления? (Даже если они обновляют один и тот же слот / переменную)?

(2) Можно ли предположить, что с учетом того, что каждый поток записывает уникальный объект, нет необходимости синхронизировать доступ к общему словарю / контейнеру?

(3) Действительно ли вызов GetLog () другим потоком создает проблемы, даже если словарь обновляется одновременно другими потоками?

Ответы [ 3 ]

3 голосов
/ 21 марта 2009

Контейнерные классы в C # не являются поточно-ориентированными для записи, что означает, что вы ДОЛЖНЫ убедиться, что только один поток получает доступ к экземпляру класса контейнера одновременно, даже если каждый поток записывает свой ключ в словаре.

Для чтения словарь является потокобезопасным, то есть вы можете читать из словаря несколько потоков одновременно. Однако читать и писать одновременно небезопасно.

Подробности здесь .

3 голосов
/ 21 марта 2009

Самая большая проблема будет, если какой-либо из потоков добавит / удалит ключ в словаре. Это может вызвать существенную перестройку внутри (вполне возможно, прервать любые конкурирующие операции чтения и записи, которые находятся в процессе), так что да; Вам нужно необходимо синхронизировать доступ. Вы могли бы быть в порядке, если бы все потоки читали / записывали против существующих ключей, но я не думаю, что это будет гарантировано.

Я не знаю о Java, но в C # есть ReaderWriterLockSlim, который может (если вам это абсолютно необходимо) разрешить несколько одновременных читателей или один писатель (не оба) - но часто проще (а иногда даже быстрее) просто перейти на мьютекс (через lock и т. д.).

редактировать

Также - для строго типизированных типов словарей (то есть обобщенных типов и т. Д.) С типами значений, размер которых превышает допустимое, обновление не будет блокироваться; другой поток теоретически может видеть текущее обновление такого значения. Например, гид по x86 и т. Д.

1 голос
/ 21 марта 2009

1) Что вы подразумеваете под «слепым обновлением»?

2) Нет. Предполагая, что Dicitonary реализован с помощью хеш-таблицы, вам необходимо синхронизировать доступ для обработки коллизий хеш-функций, увеличения размера таблицы и т. Д. Возможно, вам удастся избежать блокировки отдельных элементов таблица, а не общая блокировка для всей структуры данных в некоторых случаях, но это также накладные расходы.

3) Зависит от того, является ли обновление атомарным или нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...