LINUX.ORG.RU

Thread safe queue и сбор статистики о времение


0

1

Есть у меня код который обеспечивает асинхронное выполнение тасков.

Стандартный случай, потоко безопасная очередь, одни в нее кладут, другие берут от туда и выполняют функтор.

Есть пару ухищрений, типа дедлайнов и cancel_hook в случае если таска просрочилась. Ну т.е. кладя задачу в очередь у нее либо вызовется метод execute() либо cancel().

Нужно мне добавить возможность сбора следующей статистики. 1. Сколько задача устанавливалась в очередь (при установки в очередь как минимум нужно схватить мютекс, как максимум есть capacity и ожидания в случае если они досиг лимита) 2. Сколько по времение задача провела в очедеи то тех поо пока ее от туда не вытащили. 3. сколько выполнялась 4. все это усредненное

Как сделано сейчас: статистика хранится в самом объекте который ставится в очередь и далее везде где нужно ее замерять, она устанавливается в сам объект. И в конце из объекта она куда то там сохраняется (т.е. объект нужно еще параметризировать тем куда ее сохранять).

схематично это выглядит так: push:

  • Засеч время при входе в метод
  • захватить мютекс
  • поставить задачу в очередь
  • засеч время выхода из метода
  • отпустить мютекс

pop:

  • Захватить мютекс
  • получить задачу из очереди
  • засем время начала выполнения
  • выполнение задачи
  • зачем время завершения
  • сохранить статистику в X

Мне не нравиться, что эту статистику приходится хранить в объектe. Поидее пользователю на нее вообще насрать. Хужее, что ее надо не просто получать, ее нужно хранить и аккамулировать, т.е. мы должны напрягать пользователя тем, что бы он подумал об этом. Мне кажется логичным что эта статистика должна накапливаться в самой очереди без участия пользователя. Но так как нужно знать когда объект был пушнут и когда был попнут, эту статистику как то нужно связать с самим объектом.

Хранить что то типо отдельного маппинга это вообще не решение. Притом сбор этоq статистики происходит на разных уровнях. Если немного подумать, то видно что информацию о пуше мы может собирать только под мютексом. А статистику о выполнении задачи нужно уже собирать на уровне выше. А еще cancel() выполняется опять на другом уровне. Единственно что объединяет все эти уровни это только объект (пользовательский тип).

А теперь добавляем что все это шаблонное, и все уровни пронизаци одним шаблонным типом (который указаль пользователь). А напрягать пользователя тем, что бы его шаблонный тип отвечал нашему специальному интерфейсу для сбора статистики нехочется. Даже если все это мы сделаем за него а ему нужно просто унаследоватся.

Может кто делал такое? Посоветуйте?


Унаследоваться

А напрягать пользователя тем, что бы его шаблонный тип отвечал нашему специальному интерфейсу для сбора статистики нехочется. Даже если все это мы сделаем за него а ему нужно просто унаследоватся.

Я всегда делал так. Необходимости в шаблоне таска я вообще не вижу. Конкретная очередь работает с конкретными задачами (или ее наследниками). Этим интерфейсом ты гарантируешь наличие execute и cancel плюс имеешь возможность хранить много всякой инфы о задачах в т.ч. статистику. В самой очереди имеет смысл хранить только усредненную статистику по всем задачам.

UPD. И я вообще не понял смысла использования шаблона задачи. То есть одна очередь может работать с одной какой-то конкретной задачей что ли?

staseg ★★★★★
()
Последнее исправление: staseg (всего исправлений: 2)
Ответ на: Унаследоваться от staseg

единственное что мне нужно от пользователя это execute, и то это только с логической точки зрения, и если его небудет то все будет работать, правда выглядеть странно :). Все остальное, включая cancel, deadline и еще много чего у меня опционально, и разрешается с использование шаблонов (mpl). Зачем так? для гибкости (что бы эту «очеред» каждый мог кастомизировать под себя, «включая» или «выключая» те или иные опции). Я правда не особо уверен в выгрыше вызова пустой функции против пустого виртуального метода, но так уже сделано.

Cupper
() автор топика
Последнее исправление: Cupper (всего исправлений: 1)
Ответ на: комментарий от Cupper

Ну так а кто описывает пустую функцию cancel? В моем варианте весь интерфейс описывается в родителе, а тут? Могу представить только такой вариант:

template<typename T>
void cancel(T task){
 (void)task;}

А для нужных задач эта функция перегружается под нужный тип. Если так, я бы назвал это жутким извращением :)

staseg ★★★★★
()
Ответ на: комментарий от staseg

есть функция cancel_hook шаблонная, которая с использованием mpl определяет наличие у типа метода cancel с определенной сигнатурой, если есть - зовет его, если нет - ничего не делает.

Пляски начинались от того что очередь у меня с приоритетами. А комуто они не нужны. Поэтому когда пользователь параметризирует очередь типом у которого нет метода int priority() в недрах используется простая queue, в противном set. Есть еще пару особенностей типа приоритетов. Для единообразия все вынесено в шаблоны.

Нечто похожее сделано в boost::multi_index_container, там правдо это нужно опеределять в качестве параметров шаблона. У меня так не получилось, слишком разношорстные особенности должна поддерживать очередь.

Cupper
() автор топика
Ответ на: комментарий от Cupper

Я бы назвал такое решение неоправданно сложным с множеством слабых легко теряемых связей. «Обычное» решение через наследование задачи было бы намного понятней как в реализации, так и при эксплуатации, причем интерфейс пользовательской задачи не усложнился бы.

Ну а раз сделано так, самое гибкое наверное — в задачи, для которых нужна статистика, вводить специальное поле stats (структуру статистики), которую, при наличии, будет модифицировать очередь. Все получится в едином духе. Не знаю правда как mpl отреагирует на stats неправильного типа, я с этим никогда не работал.

staseg ★★★★★
()
Ответ на: комментарий от staseg

сейчас так и сделано. И это неочень нравится.

Cupper
() автор топика

А напрягать пользователя тем, что бы его шаблонный тип отвечал нашему специальному интерфейсу для сбора статистики нехочется. Даже если все это мы сделаем за него а ему нужно просто унаследоватся.

Где-то внутри очереди есть объект, который хранит ссылку на пользовательский эвент. Например, это может быть чанк в DLL. В чём проблема держать объект со статистикой в этом чанке? Или пушить pair<> с объектом статистики и ссылкой на эвент если нельзя залезть в реализацию очереди.

mashina ★★★★★
()
Последнее исправление: mashina (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.