Пересылка функции с переменным количеством аргументов в C++11
Пытаюсь написать обёртку над std::thread с флагом isNeedtoStop и циклом, постоянно вызывающим переданную функцию, пока isNeedToStop не установлен. Возникла трудность в том как правильно передать функцию и параметры в функцию цикла. Возможно ли это на С++11 в принципе?
class CThread
{
public:
template<typename TF, typename... TArgs>
void Start(TF&& func, TArgs&&... _args)
{
m_isNeedtoStop = false;
m_thrd = std::thread(std::bind(&CThread::Loop, this,
std::forward<TF>(func),
std::forward<TArgs>(_args)...));
}
template<typename TF, typename... TArgs>
void Loop(TF&& func, TArgs&&... _args)
{
while (!m_isNeedToStop)
{
func(_args...);
}
}
private:
std::thread m_thrd;
std::atomic<bool> m_isNeedtoStop;
};
И вызов из другого объекта:
class CTest
{
public:
void PrintHello(int a, int b, int c)
{
std::cout<<"Hello, concurrent world "<< a+b+c << std::endl;
}
void Run()
{
m_thread.Start(&CTest::PrintHello, this, 6, 7, 8);
}
private:
CThread m_thread;
};
Ответы (2 шт):
Автор решения: user7860670
→ Ссылка
Пример из С++-20, где был добавлен класс std::jthread
, имеющий встроенную поддержку флага прерывания потока. При вызове деструктора он сам выставит флажек прерывания работы и дождется завершения потока:
#include <chrono>
#include <iostream>
#include <thread>
class CTest
{
private: static void
PrintHello_Sink(::std::stop_token token, CTest * thiz, int a, int b, int c)
{
return thiz->PrintHello(token, a, b, c);
}
public: void
PrintHello(::std::stop_token token, int a, int b, int c)
{
while (not token.stop_requested())
{
::std::cout << "Hello, concurrent world " << a+b+c << ::std::endl;
::std::this_thread::sleep_for(::std::chrono::seconds{1});
}
}
public: void
Run()
{
m_thread = ::std::jthread{&CTest::PrintHello_Sink, this, 6, 7, 8};
}
private: ::std::jthread m_thread;
};
int
main()
{
CTest test{};
test.Run();
::std::this_thread::sleep_for(::std::chrono::seconds{2});
return 0;
}
Автор решения: user7860670
→ Ссылка
Вот вариант велосипедного jthread
для C++-11:
#include <atomic>
#include <chrono>
#include <iostream>
#include <memory>
#include <thread>
#include <utility>
class StopToken
{
private: ::std::shared_ptr<::std::atomic<bool>> m_p_flag;
public: StopToken()
: m_p_flag{::std::make_shared<::std::atomic<bool>>()}
{}
public: StopToken(StopToken const & other)
: m_p_flag{other.m_p_flag}
{}
public: void operator =(StopToken const & other)
{
m_p_flag = other.m_p_flag;
}
public: bool stop_requested() const noexcept
{
return *m_p_flag;
}
public: void request_stop() noexcept
{
(*m_p_flag) = true;
}
public: void reset() noexcept
{
(*m_p_flag) = false;
}
};
class JThread
{
private: StopToken m_stop_token;
private: ::std::thread m_thread;
public: JThread()
: m_stop_token{}, m_thread{}
{}
public: ~JThread() noexcept
{
Try_Join();
}
public: template<typename x_Functor, typename... x_Args>
JThread(x_Functor && functor, x_Args && ... args)
: m_stop_token{}
, m_thread{::std::forward<x_Functor>(functor), m_stop_token, ::std::forward<x_Args>(args)...}
{}
public: JThread(JThread && other)
: m_stop_token{}
, m_thread{::std::move(other.m_thread)}
{
::std::swap(m_stop_token, other.m_stop_token);
}
public: void operator =(JThread && other) noexcept
{
if (this != &other)
{
Try_Join();
m_thread = ::std::move(other.m_thread);
::std::swap(m_stop_token, other.m_stop_token);
}
}
private: void Try_Join() noexcept
{
if (m_thread.joinable())
{
m_stop_token.request_stop();
m_thread.join();
}
m_stop_token.reset();
}
};
class CTest
{
public: using
Thread = ::JThread;
public: using
StopToken = ::StopToken;
private: static void
PrintHello_Sink(StopToken token, CTest * thiz, int a, int b, int c)
{
return thiz->PrintHello(token, a, b, c);
}
public: void
PrintHello(StopToken token, int a, int b, int c)
{
while (not token.stop_requested())
{
::std::cout << "Hello, concurrent world " << a+b+c << ::std::endl;
::std::this_thread::sleep_for(::std::chrono::seconds{1});
}
}
public: void
Run()
{
m_thread = Thread{&CTest::PrintHello_Sink, this, 6, 7, 8};
}
private: Thread m_thread;
};
int
main()
{
CTest test{};
test.Run();
::std::this_thread::sleep_for(::std::chrono::seconds{2});
return 0;
}