Передать в пул потоков переменную-член из родительского класса.

Вопрос или проблема

У меня есть следующий класс:

class CMyClass
{
public:
    void TestThreadPool();

protected:
    void MyMethod();

...
protected:
    std::unique_ptr<concurrent::threadpool> m_tp{};
}

и реализация:

void CMyClass::MyMethod()
{
    std::this_thread::sleep_for(std::chrono::seconds(33));
    TRACE("CMyClass::MyMethod\n");
}

И вот здесь я хочу протестировать пул потоков:

void CMyClass::TestThreadPool()
{
    m_tp->enqueue_r(&CMyClass::MyMethod, this);
}

Пока все хорошо.

Если CMyClass будет иметь родителя:

class CServicePortal
{
public:
    void Method1(const int duration) const;
    bool Method2(const int duration) const;
    int Method3(const int duration) const;
};

и

class CMyClass: public CServicePortal
...

Как я могу добавить методы CServicePortal в пул потоков?

void CMyClass::TestThreadPool()
{
    m_tp->enqueue_r(&CMyClass::MyMethod, this);         // ок
    m_tp->enqueue_r(&CServicePortal::Method1, this);    // ошибка
    m_tp->enqueue_r(&CNetMapDoc::Method1, this); // та же ошибка
}

Ошибка говорит: 'type': is not a member of any direct or indirect base class of 'std::_Invoke_traits_nonzero<void,Fn,CNetMapDoc *&>'

П.С. Используемый пул потоков взят отсюда threadpool, но может быть использован любой другой пул потоков.

Ответ или решение

Чтобы использовать методы родительского класса CServicePortal в пуле потоков в классе CMyClass, вам необходимо правильно указать синтаксис для вызова методов, поскольку они являются частью базового класса. В C++ необходимо гарантировать, что вы передаете правильный указатель на функцию, а также корректно указываете контекст вызова.

Решение проблемы

Вам нужно использовать статический привязанный вызов (static member function) или создать лямбда-выражение для вызова методов базового класса, потому что обычный вызов не работает по причине контекста вызова.

Исправленный код

Вот как бы выглядел ваш метод TestThreadPool с учетом вызовов методов CServicePortal:

void CMyClass::TestThreadPool()
{
    // Вызов метода MyMethod из CMyClass
    m_tp->enqueue_r(&CMyClass::MyMethod, this);

    // Вызов метода Method1 из CServicePortal
    m_tp->enqueue_r([this]() { CServicePortal::Method1(33); });

    // Вызов метода Method2 из CServicePortal
    m_tp->enqueue_r([this]() { CServicePortal::Method2(33); });

    // Вызов метода Method3 из CServicePortal
    m_tp->enqueue_r([this]() { return CServicePortal::Method3(33); });
}

Пояснение

  1. Лямбда-выражение: Лямбда позволяет вам делать вызов метода базового класса, передавая контекст this, который указывает на текущий объект CMyClass и позволяет обращаться к методам CServicePortal, поскольку они являются членами этого объекта.

  2. Параметры: Если методы Method1, Method2 и Method3 требуют аргументов, как в примере const int duration, вы можете передать эти аргументы в лямбда-выражении.

  3. Возврат значения: Если метод возвращает значение (как Method3), вам нужно правильно обрабатывать его, так как результат выполнения метода не будет возвращен в стандартном потоке или пуле потоков. Если это необходимо, вы можете использовать подход с std::future.

Заключение

Использование лямбда-функций упрощает вызов методов родительского класса в пуле потоков и решает проблемы, возникающие из-за контекста вызова. С помощью этого подхода вы можете безопасно и эффективно работать с методами класса CServicePortal из CMyClass.

Оцените материал
Добавить комментарий

Капча загружается...