Я хочу, чтобы мой класс порождал два потока, которые будут работать в цикле и взаимодействовать с классом владельца.Это было легко, когда у меня сначала был один класс с одним потоком: один атомарный флаг, один мьютекс и т. Д. Но поскольку требования ко второму потоку повысились, я думаю о более элегантном решении, которое будет инкапсулировать поток и его утилиты.Например: класс ThreadWrapper, который может быть создан в классе владельца.
До сих пор я придумал следующее, однако я не уверен, что это правильный путь:
class ThreadWrapper
{
public:
ThreadWrapper()
: m_threadShouldRun(false)
, m_threadRunning(false)
{
}
ThreadWrapper(std::function<void()> fn)
: m_threadShouldRun(true)
, m_threadRunning(false)
, m_threadFunction(fn)
{
m_threadPointer = std::make_shared<std::thread>(std::thread([&] { this->threadLoop(); }));
}
virtual ~ThreadWrapper()
{
if (m_threadRunning)
m_threadShouldRun = false;
m_threadPointer->join();
m_threadPointer = nullptr;
}
private:
void threadLoop()
{
m_threadRunning = true;
while(m_threadShouldRun)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
m_threadFunction();
}
m_threadRunning = false;
}
std::function<void()> m_threadFunction = []{};
std::shared_ptr<std::thread> m_threadPointer;
std::atomic<bool> m_threadShouldRun;
std::atomic<bool> m_threadRunning;
};
Использование (исправлено):
class Foo
{
Foo()
: t1(std::function<void()>(std::bind(&Foo::internalLoop1, this)))
, t2(std::function<void()>(std::bind(&Foo::internalLoop2, this)))
{
}
ThreadWrapper t1;
ThreadWrapper t2;
std::mutex mtx;
void internalLoop1()
{
// looped task
{
std::scoped_lock lock(mtx);
// write'n'read data to tx/rx queues
}
}
void internalLoop2()
{
// looped task
{
std::scoped_lock lock(mtx);
// process the rx queue
}
}
};
Это похоже на Wrapper, который я нашел здесь .Недостатком является то, что период ожидания должен быть передан объекту ThreadWrapper.
Это правильный подход?Или, может быть, это следует сделать с помощью базового класса и просто унаследованного виртуального метода?Как показано на рисунке ниже.![Thread model from codeproj.](https://i.stack.imgur.com/ArsqA.png)
Источник: https://www.codeproject.com/Articles/18383/A-thread-wrapper-class
В идеале я хотел бы использовать шаблон здесь, однако единственная «другая» часть между ThreadWrapper - это один метод, что скорее подсказывает мне указатели наследования / функции.Или я здесь не прав?
РЕДАКТИРОВАТЬ: Мотивация.В C # можно сделать следующее: var t1 = new Thread(() => internalLoop1());
В конце я присматриваю за такой строкой в моем основном классе.Где другой класс ThreadWrapper позаботится об управлении безопасностью потока.Следовательно, легко реплицируемый, если нужно создать несколько потоков.