Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qohossinglethreadexecutor.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtCore/private/qohoslogger_p.h>
5#include <condition_variable>
6#include <cstring>
7#include <memory>
8#include <mutex>
9#include <pthread.h>
10#include <qohossinglethreadexecutor.h>
11#include <queue>
12#include <utility>
13
14QT_BEGIN_NAMESPACE
15
16namespace QtOhos {
17
18namespace {
19
20std::shared_ptr<::pthread_attr_t> makePthreadAttr()
21{
22 auto threadAttrStorage = std::make_shared<::pthread_attr_t>();
23 auto threadAttr = std::shared_ptr<::pthread_attr_t>(
24 threadAttrStorage.get(),
25 [threadAttrStorage](::pthread_attr_t *attr) {
26 ::pthread_attr_destroy(attr);
27 });
28
29 int initResult = ::pthread_attr_init(threadAttr.get());
30 if (initResult != 0)
31 qOhosReportFatalErrorAndAbort("pthread_attr_init() failed: %s", std::strerror(initResult));
32
33 return threadAttr;
34}
35
36std::shared_ptr<void> startNewThread(
37 std::function<void()> threadFunction, const ::pthread_attr_t &threadAttributes)
38{
39 struct Context
40 {
41 std::function<void()> threadFunction;
42 QOhosOptional<::pthread_t> optThreadId;
43 };
44
45 auto context = std::make_shared<Context>();
46 context->threadFunction = std::move(threadFunction);
47
48 auto threadHandle = makeDestroyNotifier(
49 [context]() {
50 if (context->optThreadId.hasValue())
51 ::pthread_join(context->optThreadId.value(), nullptr);
52 });
53
54 auto pthreadStartRoutineFunc = [](void *arg) -> void * {
55 auto *context = static_cast<Context *>(arg);
56 context->threadFunction();
57 return nullptr;
58 };
59
60 ::pthread_t threadId;
61 int createResult = ::pthread_create(&threadId, &threadAttributes, pthreadStartRoutineFunc, context.get());
62 if (createResult != 0) {
63 qOhosReportFatalErrorAndAbort(
64 "%s: pthread_create() failed: %s", Q_FUNC_INFO, std::strerror(createResult));
65 }
66
67 context->optThreadId = threadId;
68
69 return threadHandle;
70}
71
72std::shared_ptr<::pthread_attr_t> createSingleThreadExecutorThreadAttributes(
73 const SingleThreadExecutorConfig &config)
74{
75 auto threadAttributes = makePthreadAttr();
76
77 if (config.threadPreferredStackSize.hasValue()) {
78 int setStackSizeResult = ::pthread_attr_setstacksize(
79 threadAttributes.get(), config.threadPreferredStackSize.value());
80 if (setStackSizeResult != 0) {
81 qOhosPrintfWarning(
82 "%s: pthread_attr_setstacksize() failed: %s",
83 Q_FUNC_INFO, std::strerror(setStackSizeResult));
84 }
85 }
86
87 return threadAttributes;
88}
89
90class SingleThreadExecutor
91{
92public:
93 SingleThreadExecutor(const SingleThreadExecutorConfig &config);
94
95 ~SingleThreadExecutor();
96
97 void enqueueTask(std::function<void()> task);
98
99private:
100 std::shared_ptr<void> m_workerThreadHandle;
101 std::mutex m_tasksQueueMutex;
102 std::queue<std::function<void()>> m_tasksQueue;
103 std::condition_variable m_tasksQueueNonEmptyCv;
104};
105
106SingleThreadExecutor::SingleThreadExecutor(const SingleThreadExecutorConfig &config)
107{
108 m_workerThreadHandle = startNewThread(
109 [this]() {
110 while (true) {
111 std::function<void()> task;
112
113 {
114 std::unique_lock<std::mutex> tasksQueueLock(m_tasksQueueMutex);
115 m_tasksQueueNonEmptyCv.wait(
116 tasksQueueLock,
117 [&]() {
118 return !m_tasksQueue.empty();
119 });
120
121 task = std::move(m_tasksQueue.front());
122 m_tasksQueue.pop();
123 }
124
125 if (!task)
126 break;
127
128 task();
129 }
130 },
131 *createSingleThreadExecutorThreadAttributes(config));
132}
133
134SingleThreadExecutor::~SingleThreadExecutor()
135{
136 enqueueTask({});
137 m_workerThreadHandle.reset();
138}
139
140void SingleThreadExecutor::enqueueTask(std::function<void()> task)
141{
142 std::lock_guard<std::mutex> tasksQueueLock(m_tasksQueueMutex);
143 m_tasksQueue.push(std::move(task));
144 m_tasksQueueNonEmptyCv.notify_one();
145}
146
147}
148
150{
151 auto executor = std::make_shared<SingleThreadExecutor>(config);
152 return [executor](std::function<void()> task) {
153 executor->enqueueTask(std::move(task));
154 };
155}
156
157}
158
159QT_END_NAMESPACE
std::enable_if_t< qohosplugincore_h_detail::isQOhosOptional< QOhosInvokeResult< Func, T > >, QOhosInvokeResult< Func, T > > andThen(Func &&func) const
QOhosConsumer< std::function< void()> > makeSingleThreadExecutor(const SingleThreadExecutorConfig &config={})