8#include <dtkcore_global.h>
12#include <QCoreApplication>
16#if DTK_VERSION >= DTK_VERSION_CHECK(6, 0, 0, 0)
24#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0)
25namespace DThreadUtil {
26typedef std::function<void()> FunctionType;
28class LIBDTKCORESHARED_EXPORT FunctionCallProxy :
public QObject
32 explicit FunctionCallProxy(QThread *thread);
34 static void proxyCall(QSemaphore *s, QThread *thread, QObject *target, FunctionType fun);
37 void callInLiveThread(QSemaphore *s, QPointer<QObject> target, FunctionType *func);
40template <
typename ReturnType>
41class LIBDTKCORESHARED_EXPORT _TMP
44 inline static ReturnType runInThread(QSemaphore *s, QThread *thread, QObject *target, std::function<ReturnType()> fun)
47 FunctionType proxyFun = [&result, &fun] () {
51 FunctionCallProxy::proxyCall(s, thread, target, proxyFun);
56 inline static typename std::enable_if<!std::is_base_of<QObject, T>::value, ReturnType>::type
57 runInThread(QSemaphore *s, QThread *thread, T *, std::function<ReturnType()> fun)
59 return runInThread(s, thread,
static_cast<QObject*
>(
nullptr), fun);
63class LIBDTKCORESHARED_EXPORT _TMP<void>
66 inline static void runInThread(QSemaphore *s, QThread *thread, QObject *target, std::function<
void()> fun)
68 FunctionCallProxy::proxyCall(s, thread, target, fun);
72 inline static typename std::enable_if<!std::is_base_of<QObject, T>::value,
void>::type
73 runInThread(QSemaphore *s, QThread *thread, T *, std::function<
void()> fun)
75 return runInThread(s, thread,
static_cast<QObject*
>(
nullptr), fun);
79template <
typename Fun,
typename... Args>
80inline auto runInThread(QSemaphore *s, QThread *thread, QObject *target, Fun fun, Args&&... args) ->
decltype(fun(args...))
82 return _TMP<
decltype(fun(args...))>::runInThread(s, thread, target, std::bind(fun, std::forward<Args>(args)...));
84template <
typename Fun,
typename... Args>
85inline auto runInThread(QSemaphore *s, QThread *thread, Fun fun, Args&&... args) ->
decltype(fun(args...))
87 return runInThread(s, thread,
nullptr, fun, std::forward<Args>(args)...);
89template <
typename Fun,
typename... Args>
90inline typename QtPrivate::FunctionPointer<Fun>::ReturnType
91 runInThread(QSemaphore *s, QThread *thread, QObject *target,
typename QtPrivate::FunctionPointer<Fun>::Object *obj, Fun fun, Args&&... args)
93 return _TMP<typename QtPrivate::FunctionPointer<Fun>::ReturnType>::runInThread(s, thread, target, std::bind(fun, obj, std::forward<Args>(args)...));
95template <
typename Fun,
typename... Args>
96inline typename QtPrivate::FunctionPointer<Fun>::ReturnType
97 runInThread(QSemaphore *s, QThread *thread,
typename QtPrivate::FunctionPointer<Fun>::Object *obj, Fun fun, Args&&... args)
99 return _TMP<typename QtPrivate::FunctionPointer<Fun>::ReturnType>::runInThread(s, thread, obj, std::bind(fun, obj, std::forward<Args>(args)...));
102template <
typename Fun,
typename... Args>
103inline auto runInThread(QThread *thread, QObject *target, Fun fun, Args&&... args) ->
decltype(fun(args...))
107 return runInThread(&s, thread, target, fun, std::forward<Args>(args)...);
109template <
typename Fun,
typename... Args>
110inline auto runInThread(QThread *thread, Fun fun, Args&&... args) ->
decltype(fun(args...))
112 return runInThread(thread,
nullptr, fun, std::forward<Args>(args)...);
114template <
typename T,
typename Fun,
typename... Args>
115inline typename QtPrivate::FunctionPointer<Fun>::ReturnType
116 runInThread(QThread *thread, T *target,
typename QtPrivate::FunctionPointer<Fun>::Object *obj, Fun fun, Args&&... args)
120 return runInThread(&s, thread, target, obj, fun, std::forward<Args>(args)...);
123template <
typename Fun,
typename... Args>
124inline typename QtPrivate::FunctionPointer<Fun>::ReturnType
125 runInThread(QThread *thread,
typename QtPrivate::FunctionPointer<Fun>::Object *obj, Fun fun, Args&&... args)
127 return runInThread(thread, obj, obj, fun, std::forward<Args>(args)...);
130template <
typename Fun,
typename... Args>
131inline auto runInMainThread(QObject *target, Fun fun, Args&&... args) ->
decltype(fun(args...))
133 if (!QCoreApplication::instance()) {
134 return fun(std::forward<Args>(args)...);
137 return runInThread(QCoreApplication::instance()->thread(), target, fun, std::forward<Args>(args)...);
139template <
typename Fun,
typename... Args>
140inline auto runInMainThread(Fun fun, Args&&... args) ->
decltype(fun(args...))
142 return runInMainThread(
nullptr, fun, std::forward<Args>(args)...);
145template <
typename T,
typename Fun,
typename... Args>
146inline typename QtPrivate::FunctionPointer<Fun>::ReturnType
147 runInMainThread(T *target,
typename QtPrivate::FunctionPointer<Fun>::Object *obj, Fun fun, Args&&... args)
149 if (!QCoreApplication::instance()) {
150 return (obj->*fun)(std::forward<Args>(args)...);
153 return runInThread(QCoreApplication::instance()->thread(), target, obj, fun, std::forward<Args>(args)...);
155template <
typename Fun,
typename... Args>
156inline typename QtPrivate::FunctionPointer<Fun>::ReturnType
157 runInMainThread(
typename QtPrivate::FunctionPointer<Fun>::Object *obj, Fun fun, Args&&... args)
159 return runInMainThread(obj, obj, fun, std::forward<Args>(args)...);
174 template <typename Func, typename... Args>
175 inline auto run(QObject *context,typename QtPrivate::FunctionPointer<Func>::Object *obj, Func fun, Args &&...args)
177 return call(context, fun, *obj, std::forward<Args>(args)...);
179 template <
typename Func,
typename... Args>
180 inline auto run(
typename QtPrivate::FunctionPointer<Func>::Object *obj, Func fun, Args &&...args)
182 if constexpr (std::is_base_of<QObject, typename QtPrivate::FunctionPointer<Func>::Object>::value) {
183 return call(obj, fun, *obj, std::forward<Args>(args)...);
185 return call(
static_cast<QObject *
>(
nullptr), fun, *obj, std::forward<Args>(args)...);
188 template <
typename Func,
typename... Args>
189 inline QFuture<std::invoke_result_t<std::decay_t<Func>, Args...>> run(QObject *context, Func fun, Args &&...args)
191 return call(context, fun, std::forward<Args>(args)...);
193 template <
typename Func,
typename... Args>
194 inline QFuture<std::invoke_result_t<std::decay_t<Func>, Args...>> run(Func fun, Args &&...args)
196 return call(
static_cast<QObject *
>(
nullptr), fun, std::forward<Args>(args)...);
198 template <
typename... T>
199 inline decltype(
auto) exec(T &&...args)
201 auto future = run(std::forward<T>(args)...);
202 if (!thread()->isRunning()) {
203 qWarning() <<
"The target thread is not running, maybe lead to deadlock.";
205 future.waitForFinished();
206 if constexpr (std::is_same_v<
decltype(future), QFuture<void>>) {
209 return future.result();
214 class AbstractCallEvent :
public QEvent
217 AbstractCallEvent(QEvent::Type type)
221 virtual void call() = 0;
224 template <
typename Func,
typename... Args>
225 class Q_DECL_HIDDEN CallEvent :
public AbstractCallEvent
227 using FunInfo = QtPrivate::FunctionPointer<std::decay_t<Func>>;
228 using ReturnType = std::invoke_result_t<std::decay_t<Func>, Args...>;
231 CallEvent(QEvent::Type type, Func &&fun, Args &&...args)
232 : AbstractCallEvent(type)
233 , function(std::forward<Func>(fun))
234 , arguments(std::forward<Args>(args)...)
238 QEvent *clone()
const override {
return nullptr; }
242 if (promise.isCanceled()) {
246 if (contextChecker == context) {
248#ifndef QT_NO_EXCEPTIONS
251 if constexpr (std::is_void_v<ReturnType>) {
252 std::apply(function, arguments);
254 promise.addResult(std::apply(function, arguments));
256#ifndef QT_NO_EXCEPTIONS
258 promise.setException(std::current_exception());
264 promise.setException(std::make_exception_ptr(std::runtime_error(
"The context object is destroyed.")));
270 const std::tuple<Args...> arguments;
271 QPromise<ReturnType> promise;
273 QObject *context{
nullptr};
274 QPointer<QObject> contextChecker;
277 template <
typename Func,
typename... Args>
278 inline auto call(QObject *context, Func fun, Args &&...args)
280 using FuncInfo = QtPrivate::FunctionPointer<std::decay_t<Func>>;
281 using ReturnType = std::invoke_result_t<std::decay_t<Func>, Args...> ;
283 if constexpr (FuncInfo::IsPointerToMemberFunction) {
284 static_assert(std::is_same_v<std::decay_t<
typename QtPrivate::List<Args...>::Car>,
typename FuncInfo::Object>,
285 "The obj and function are not compatible.");
287 QtPrivate::CheckCompatibleArguments<
typename QtPrivate::List<Args...>::Cdr,
typename FuncInfo::Arguments>::value,
288 "The args and function are not compatible.");
289 }
else if constexpr (FuncInfo::ArgumentCount != -1) {
290 static_assert(QtPrivate::CheckCompatibleArguments<QtPrivate::List<Args...>,
typename FuncInfo::Arguments>::value,
291 "The args and function are not compatible.");
293 static_assert(std::is_invocable_r_v<ReturnType, Func, Args...>,
294 "The callable object can't invoke with supplied args");
297 QPromise<ReturnType> promise;
298 auto future = promise.future();
300 if (Q_UNLIKELY(QThread::currentThread() == m_thread)) {
302 if constexpr (std::is_void_v<ReturnType>) {
303 std::invoke(fun, std::forward<Args>(args)...);
305 promise.addResult(std::invoke(fun, std::forward<Args>(args)...));
309 auto event =
new CallEvent<Func, Args...>(eventType, std::move(fun), std::forward<Args>(args)...);
310 event->promise = std::move(promise);
311 event->context = context;
312 event->contextChecker = context;
314 QCoreApplication::postEvent(ensureThreadContextObject(), event);
320 QObject *ensureThreadContextObject();
322 static inline QEvent::Type eventType;
324 QAtomicPointer<QObject> threadContext;
Definition dthreadutils.h:164
QThread * thread() const noexcept
获取DThreadUtils对应的线程
static DThreadUtils & gui()
获取以GUI线程初始化的静态对象