4#include <QtCore/private/qohoslogger_p.h>
5#include <condition_variable>
10#include <qohossinglethreadexecutor.h>
19std::shared_ptr<::pthread_attr_t> makePthreadAttr()
21 auto threadAttrStorage =
std::make_shared<::pthread_attr_t>();
22 auto threadAttr =
std::shared_ptr<::pthread_attr_t>(
23 threadAttrStorage.get(),
24 [threadAttrStorage](::pthread_attr_t *attr) {
25 ::pthread_attr_destroy(attr);
28 int initResult = ::pthread_attr_init(threadAttr.get());
30 qOhosReportFatalErrorAndAbort(
"pthread_attr_init() failed: %s",
std::strerror(initResult));
35std::shared_ptr<
void> startNewThread(
36 std::function<
void()> threadFunction,
const ::pthread_attr_t &threadAttributes)
40 std::function<
void()> threadFunction;
41 std::optional<::pthread_t> optThreadId;
44 auto context =
std::make_shared<Context>();
45 context->threadFunction =
std::move(threadFunction);
47 auto threadHandle = makeDestroyNotifier(
49 if (context->optThreadId.has_value())
50 ::pthread_join(context->optThreadId.value(),
nullptr);
53 auto pthreadStartRoutineFunc = [](
void *arg) ->
void * {
54 auto *context =
static_cast<Context *>(arg);
55 context->threadFunction();
60 int createResult = ::pthread_create(&threadId, &threadAttributes, pthreadStartRoutineFunc, context.get());
61 if (createResult != 0) {
62 qOhosReportFatalErrorAndAbort(
63 "%s: pthread_create() failed: %s", Q_FUNC_INFO,
std::strerror(createResult));
66 context->optThreadId = threadId;
71std::shared_ptr<::pthread_attr_t> createSingleThreadExecutorThreadAttributes(
74 auto threadAttributes = makePthreadAttr();
76 if (config.threadPreferredStackSize.has_value()) {
77 int setStackSizeResult = ::pthread_attr_setstacksize(
78 threadAttributes.get(), config.threadPreferredStackSize.value());
79 if (setStackSizeResult != 0) {
81 "%s: pthread_attr_setstacksize() failed: %s",
82 Q_FUNC_INFO,
std::strerror(setStackSizeResult));
86 return threadAttributes;
89class SingleThreadExecutor
94 ~SingleThreadExecutor();
96 void enqueueTask(
std::function<
void()> task);
99 std::shared_ptr<
void> m_workerThreadHandle;
100 std::mutex m_tasksQueueMutex;
101 std::queue<std::function<
void()>> m_tasksQueue;
102 std::condition_variable m_tasksQueueNonEmptyCv;
107 m_workerThreadHandle = startNewThread(
110 std::function<
void()> task;
113 std::unique_lock<std::mutex> tasksQueueLock(m_tasksQueueMutex);
114 m_tasksQueueNonEmptyCv.wait(
117 return !m_tasksQueue.empty();
120 task = std::move(m_tasksQueue.front());
130 *createSingleThreadExecutorThreadAttributes(config));
133SingleThreadExecutor::~SingleThreadExecutor()
136 m_workerThreadHandle.reset();
139void SingleThreadExecutor::enqueueTask(
std::function<
void()> task)
141 std::lock_guard<
std::mutex> tasksQueueLock(m_tasksQueueMutex);
142 m_tasksQueue.push(std::move(task));
143 m_tasksQueueNonEmptyCv.notify_one();
150 auto executor =
std::make_shared<SingleThreadExecutor>(config);
151 return [executor](
std::function<
void()> task) {
152 executor->enqueueTask(
std::move(task));
QOhosConsumer< std::function< void()> > makeSingleThreadExecutor(const SingleThreadExecutorConfig &config={})