Есть сервер. Потоки (отвечающие на запросы) используют для чтения некоторую структуру данных. Раз в час сервер обновляет эту структуру данных. Сейчас для обеспечения конкуррентной работы использую RWLock. (при чтении поток ставит read lock, при обновлении write lock). Всё работает нормально, но во время обновления структуры, новые запросы вынуждены ждать уже выполняющиеся, длинные запросы.
Для решения проблемы можно было бы в каждом потоке создавать копию этой структуры, но это может быть довольно накладно. По этому, предлагается следующее решение:
— может существовать несколько версий объекта;
— время жизни каждой версии управляется с помощью shared_ptr;
— для чтения объекта, берётся самая новая копия (метод const shared_ptr<T> get() const);
— для изменения объекта, создаётся новый объект (например, объект сначала копируется, затем модифицируется), и добавляется к списку версий (метод void replace(const T &));
— для того, чтобы запретить одновременное изменение объекта, можно использовать обычный mutex;
— список версий состоит из одного элемента — указателя на последнюю версию, для его изменения используется атомарный swap;
Реализовано ли это, например, в boost, или прийдётся писать велосипед (на первый взгляд, решение не сложное)?
Здравствуйте, Аноним, Вы писали:
А>Реализовано ли это, например, в boost, или прийдётся писать велосипед (на первый взгляд, решение не сложное)?
Прямо в таком виде — нет, но, на первый взгляд, можно реализовать при помощи Boost.Flyweight (тебе понадобится своя factory, которая всегда будет отдавать только последнюю версию объекта). http://www.boost.org/libs/flyweight/doc/index.html
Но и руками закодировать всю эту радость должно быть просто.
Здравствуйте, Аноним, Вы писали:
А>- список версий состоит из одного элемента — указателя на последнюю версию, для его изменения используется атомарный swap;
кстати, в новом стандарте у shared_ptr будут атомарные операции типа atomic_swap, так что не придется городить огород с мьютексами и дополнительными указателями.
Здравствуйте, Аноним, Вы писали:
А>Есть сервер. Потоки (отвечающие на запросы) используют для чтения некоторую структуру данных. Раз в час сервер обновляет эту структуру данных. Сейчас для обеспечения конкуррентной работы использую RWLock. (при чтении поток ставит read lock, при обновлении write lock). Всё работает нормально, но во время обновления структуры, новые запросы вынуждены ждать уже выполняющиеся, длинные запросы. А>Для решения проблемы можно было бы в каждом потоке создавать копию этой структуры, но это может быть довольно накладно. По этому, предлагается следующее решение:
Может оно и нужно, но не в вашем случае.
Если обновления быстрые а чтение долгое, то делается очередь обновлений в которую кидаются обновления если структура занята, а потом любой поток в соответствии с приоритетами может выполнить ожидающие обновления.
Здравствуйте, Аноним, Вы писали:
А>>Есть сервер. Потоки (отвечающие на запросы) используют для чтения некоторую структуру данных. Раз в час сервер обновляет эту структуру данных. Сейчас для обеспечения конкуррентной работы использую RWLock. (при чтении поток ставит read lock, при обновлении write lock). Всё работает нормально, но во время обновления структуры, новые запросы вынуждены ждать уже выполняющиеся, длинные запросы. А>>Для решения проблемы можно было бы в каждом потоке создавать копию этой структуры, но это может быть довольно накладно. По этому, предлагается следующее решение:
А>Может оно и нужно, но не в вашем случае. А>Если обновления быстрые а чтение долгое, то делается очередь обновлений в которую кидаются обновления если структура занята, а потом любой поток в соответствии с приоритетами может выполнить ожидающие обновления.
Это решит ровно ноль проблем и добавит новые. Нет никакой разницы, сделает обновление поток Q или поток W, обновляющему потоку всё равно придётся делать ту же самую плохую вещь — блокировать читающие потоки.
Плюс это ломает последовательную консистентность: если поток добавляет элемент в коллекцию, а потом ищет его, то он должен его находить. При использовании отложенного обновления поток может не найти элемент, который он только что вставил.
Здравствуйте, Аноним, Вы писали:
А>Есть сервер. Потоки (отвечающие на запросы) используют для чтения некоторую структуру данных. Раз в час сервер обновляет эту структуру данных. Сейчас для обеспечения конкуррентной работы использую RWLock. (при чтении поток ставит read lock, при обновлении write lock). Всё работает нормально, но во время обновления структуры, новые запросы вынуждены ждать уже выполняющиеся, длинные запросы. А>Для решения проблемы можно было бы в каждом потоке создавать копию этой структуры, но это может быть довольно накладно. По этому, предлагается следующее решение: А>- может существовать несколько версий объекта; А>- время жизни каждой версии управляется с помощью shared_ptr; А>- для чтения объекта, берётся самая новая копия (метод const shared_ptr<T> get() const); А>- для изменения объекта, создаётся новый объект (например, объект сначала копируется, затем модифицируется), и добавляется к списку версий (метод void replace(const T &)); А>- для того, чтобы запретить одновременное изменение объекта, можно использовать обычный mutex; А>- список версий состоит из одного элемента — указателя на последнюю версию, для его изменения используется атомарный swap; А>Реализовано ли это, например, в boost, или прийдётся писать велосипед (на первый взгляд, решение не сложное)?
Список версий тут не нужен. Каждый старый объект может "доживать свой век" независимо от других объектов, просто когда последний читатель закончит работу с объектом, он удалит его.
Тут нужен просто shared_ptr+mutex:
Здравствуйте, remark, Вы писали:
А>>- список версий состоит из одного элемента — указателя на последнюю версию, для его изменения используется атомарный swap;
R>Список версий тут не нужен.
Так он сам вроде к этому и пришел в результате, см. выделенное
Здравствуйте, jazzer, Вы писали:
А>>>- список версий состоит из одного элемента — указателя на последнюю версию, для его изменения используется атомарный swap;
R>>Список версий тут не нужен. J>Так он сам вроде к этому и пришел в результате, см. выделенное
Ну может, не знаю, меня смутило:
для изменения объекта, создаётся новый объект, и добавляется к списку версий
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, remark, Вы писали:
R>>Без списка тут и писать, и искать готовое нечего.
J>Угу, особенно с С++0х-овым atomic_swap|atomic_store. Даже мьютексы никакие не нужны