Иногда нам требуется выполнение задачи при определённых условиях. Для решения этой проблемы используются условные задачи (WFConditional).
Условная задача представляет собой обёртку для любой задачи, заменяющую её. Выполнение обёрнутой задачи происходит после отправки сигнала в условную задачу.
Создание условной задачи осуществляется через интерфейсы фабрики WFTaskFactory:
class WFTaskFactory
{
public:
static WFConditional *create_conditional(SubTask *task);
static WFConditional *create_conditional(SubTask *task, void **msgbuf);
};
Здесь task
— это задача, которую мы хотим обернуть, а msgbuf
— буфер для получения сообщений. В случае, если конкретное содержимое сообщений нас не интересует, можно пропустить этот параметр.
Основные методы класса WFConditional:
class WFConditional : public WFGenericTask
{
public:
virtual void signal(void *msg);
...
};
Метод signal()
используется для отправки сигнала, который активирует выполнение обёрнутой задачи.
Приведём пример создания задержки выполнения вычислительной задачи на одну секунду с использованием таймера и условной задачи:
int main()
{
WFGoTask *task = WFTaskFactory::create_go_task("test", [](){ printf("Done\n"); });
WFConditional *cond = WFTaskFactory::create_conditional(task);
WFTimerTask *timer = WFTaskFactory::create_timer_task(1, 0, [cond](void *){
cond->signal(NULL);
});
timer->start();
cond->start();
getchar();
}
В этом примере сигнал для активации задачи отправляется из обратного вызова таймера. Независимо от того, какой из этих методов (cond->signal()
или cond->start()
) будет вызван первым, программа будет работать корректно.
Для удобства управления сигналами была внедрена реализация паттерна наблюдатель. Это позволяет отправлять сигналы по имени, что упрощает управление множеством условных задач.
Создание названных условных задач отличается наличием имени кондиционера:
class WFTaskFactory
{
public:
static WFConditional *create_conditional(const std::string& cond_name, SubTask *task);
static WFConditional *create_conditional(const std::stdring& cond_name, SubTask *task, void **msgbuf);
static int signal_by_name(const std::string& cond_name, void *msg);
static int signal_by_name(const std::string& cond_name, void *msg, size_t max);
template<typename T>
static int signal_by_name(const std::string& cond_name, T *const msg[], size_t max);
};
Функция signal_by_name()
отправляет сигнал всем задачам, ожидающим его под указанным именем. Также можно использовать параметр max
, чтобы ограничить количество активируемых задач.
Рассмотрим пример, где два вычислительных задания выполняются одновременно при помощи паттерна наблюдатель:
int main()
{
WFGoTask *task1 = WFTaskFactory::create_go_task("test", [](){ printf("test1 done\n"); });
WFGoTask *task2 = WFTaskFactory::create_go_task("test", [](){ printf("test2 done\n"); });
WFConditional *cond1 = WFTaskFactory::create_conditional("slot1", task1);
WFConditional *cond2 = WFTaskFactory::create_conditional("slot1", task2);
WFTimerTask *timer = WFTaskFactory::create_timer_task(1, 0, [](void *){
WFTaskFactory::signal_by_name("slot1", NULL);
});
timer->start();
cond1->start();
cond2->start();
getchar();
}
Здесь таймер отправляет сигнал всем задачам, ожидающим его под именем "slot1".
Любую задачу можно прекратить выполнение путём вызова метода dismiss
. Однако для условных задач важно убедиться, что они не были активированы перед тем как их отменять.
Например, следующий код может повести себя некорректно:
int main()
{
WFEmptyTask *task = WFTaskFactory::create_empty_task();
WFConditional *cond = WFTaskFactory::create_conditional("slot1", task);
WFTimerTask *timer = WFTaskFactory::create_timer_task(0, 0, [](void *) {
WFTaskFactory::signal_by_name("slot1");
});
timer->start();
cond->dismiss(); // Отмена задачи
getchar();
}
Если обратный вызов таймера уже активировал сигнал, то дальнейшая отмена задачи будет некорректной. Такое поведение возможно только для названных условных задач, поэтому следует быть осторожными при отмене таких задач.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )