Вопрос или проблема
У меня есть следующий класс:
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); });
}
Пояснение
-
Лямбда-выражение: Лямбда позволяет вам делать вызов метода базового класса, передавая контекст
this
, который указывает на текущий объектCMyClass
и позволяет обращаться к методамCServicePortal
, поскольку они являются членами этого объекта. -
Параметры: Если методы
Method1
,Method2
иMethod3
требуют аргументов, как в примереconst int duration
, вы можете передать эти аргументы в лямбда-выражении. -
Возврат значения: Если метод возвращает значение (как
Method3
), вам нужно правильно обрабатывать его, так как результат выполнения метода не будет возвращен в стандартном потоке или пуле потоков. Если это необходимо, вы можете использовать подход сstd::future
.
Заключение
Использование лямбда-функций упрощает вызов методов родительского класса в пуле потоков и решает проблемы, возникающие из-за контекста вызова. С помощью этого подхода вы можете безопасно и эффективно работать с методами класса CServicePortal
из CMyClass
.