Ситуация следующая:
Имеется массив объектов(несколько тысяч). Каждый объект находится каком-то состоянии(3-10 состояний),
3 рабочих потока пользуются этим массивом. Каждый рабочий может смотреть и изменять
состояния объектов. +Имеется еще и интерфейсный поток(пока только просмотр состояний
объектов). Разумеется необходима синхронизация.
1.Одна Критическая секция для всего массива.
Минусы — читает только один все остальные ждут.
2.Два события для всего массива (одно для читателей другое для писателей) читают все одновременно,
пишет только 1.
Минусы — Пишущий поток по прежнему блокирует массив.
3. Вариант 2, но для каждого экземпляра.
Помоему так недьзя(количество HANDLOV у ОС конечно).
Есть у меня предложение... Не блестящее, конечно... Я бы попроюовал что-то среднее между пунктами 1 и 3, т.е. организовал бы семафорчик для каждой 100(1000) элементов. Тогда, если потоки работают с массивом "вразнобой", это может быть разумным компромисом...
Здравствуйте yogi, Вы писали:
Y>Здравствуйте User99,
Y>Есть у меня предложение... Не блестящее, конечно... Я бы попроюовал что-то среднее между пунктами 1 и 3, т.е. организовал бы семафорчик для каждой 100(1000) элементов. Тогда, если потоки работают с массивом "вразнобой", это может быть разумным компромисом...
Спасибо Интересует также мнение насчет приведенного варианта.
В голову приходит только одно — нужен централизованных блокировщик, к которому будут обращаться
рабочие потоки для получения монопольного доступа к элементу.
Массив, наверное, во время работы может менять размеры?
Вообщем, клёвая задача.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте User99, Вы писали: U>Ваше мнение по поводу всего этого. Повторюсь размер массива 1000-60000;
Думаю что Вам может помочь семейтсво функций Interlocked:
LONG InterlockedExchangeAdd(PLONG plAddend, LONG lIncrement);
Добавление величины
Рихтер пишет, что она гарантирует приращение значения переменной
на уровне атомарного доступа,
т.е. без прерывания другими потоками
LONG InterlockedExchange(PLONG plTarget, LONG lValue);
Здравствуйте User99, Вы писали:
U>Ситуация следующая: U>Имеется массив объектов(несколько тысяч). Каждый объект находится каком-то состоянии(3-10 состояний), U>3 рабочих потока пользуются этим массивом. Каждый рабочий может смотреть и изменять U>состояния объектов. +Имеется еще и интерфейсный поток(пока только просмотр состояний U>объектов). Разумеется необходима синхронизация. U>1.Одна Критическая секция для всего массива. U> Минусы — читает только один все остальные ждут. U>2.Два события для всего массива (одно для читателей другое для писателей) читают все одновременно, U>пишет только 1. U> Минусы — Пишущий поток по прежнему блокирует массив.
U>3. Вариант 2, но для каждого экземпляра. U> Помоему так недьзя(количество HANDLOV у ОС конечно).
Если я не ошибаюсь, то можно создать семафоры, которые будут иметь по Handle на поток и небольшую структуру на каждый блокируемый элемент. При этом читать могут несколько потоков (shared access), а читать/писать один (exclusive access). U>4.
U>
Мне кажется, что в данном случае надо организовать синхронизацию не на уровне элементов массива(вариант 3), а на уровне читателей-писателей, т. е. объекты синхронизации создаются не для каждого элемента массива, а для каждого читателя-писателя(ведь именно их и надо разделить). При обращению к элементу проверять, не занят ли он кем, если занят, то ждать освобождения. А заботу о сигнализации освобождения элемента возложить на того, кто его занял. Получится некий массив: кто занял и что занял.
Здравствуйте Vogul, Вы писали:
V>Здравствуйте User99, Вы писали:
V>Мне кажется, что в данном случае надо организовать синхронизацию не на уровне элементов массива(вариант 3), а на уровне читателей-писателей, т. е. объекты синхронизации создаются не для каждого элемента массива, а для каждого читателя-писателя(ведь именно их и надо разделить). При обращению к элементу проверять, не занят ли он кем, если занят, то ждать освобождения. А заботу о сигнализации освобождения элемента возложить на того, кто его занял. Получится некий массив: кто занял и что занял.
Есть недокументированные функции Windows NT для блокировки "Читатель/Писатель". О них написано в "Windows Developer's Journal" Jan 99. С сайта журнала можно скачать архив с С++ кодом: ftp://ftp.wdj.com/pub/1999/jan99.zip (нужный файл называется claar.zip).
Еще блокировка "Читатель/Писатель" описана в книжке "Designing solutions with COM+ Technologies".
Это очень похоже на базу данных:
Есть длинная (1000-60000 записей) таблица; несколько клиентов читают/пишут различные записи.
Сервера, построенные на pessimistic locking, типа MS SQL, создают специальные объекты "lock" — это некоторый аналог синхронизационных объектов операционной системы. Для того, чтобы оптимизировать количество локов, они используют переменную гранулярность. Т.е. лок может быть поставлен на отдельную запись, страницу (несколько записей, идущих друг за другом), или всю таблицу.
Вообще говоря, количество локов, поставленных одновременно, зависит от количества одновременных транзакций и от их "длины", т.е. количества изменяемых элементов.
Смысл в том, что локи создаются динамически, т.е. нет предопределенных объектов, созданных для каждой записи. Лок менеджер управляет доступом к данным и "раздает" их динамически. В твоем случае имеет смысл сделать вторичную структуру, которая описывает "залоченность" объектов, и прогонять все операторы доступа через нее. Тогда будет один постоянный синхронизационный объект — на вторичную структуру, а она, в свою очередь, будет динамически использовать необходимое количество синхронизационных объектов для управления доступом к основным данным. Если у тебя каждая транзакция читает/записывает только один объект, то не надо никакой гранулярности, а количество этих локов будет равно количеству потоков, независимо от размера данных (количества объектов)
Уйдемте отсюда, Румата! У вас слишком богатые погреба.