1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/sogou-workflow

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
about-conditional.md 6.3 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 01.03.2025 10:20 552780a

Условные задачи и паттерн наблюдателя

Иногда нам требуется выполнение задачи при определённых условиях. Для решения этой проблемы используются условные задачи (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 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/sogou-workflow.git
git@api.gitlife.ru:oschina-mirror/sogou-workflow.git
oschina-mirror
sogou-workflow
sogou-workflow
master