DtkCore
DTK Core module
dthreadutils.h
1// SPDX-FileCopyrightText: 2020 - 2022 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: LGPL-3.0-or-later
4
5#ifndef DTHREADUTILS_H
6#define DTHREADUTILS_H
7
8#include <dtkcore_global.h>
9#include <QObject>
10#include <QSemaphore>
11#include <QThread>
12#include <QCoreApplication>
13#include <QPointer>
14#include <QDebug>
15
16DCORE_BEGIN_NAMESPACE
17
18namespace DThreadUtil {
19typedef std::function<void()> FunctionType;
20
21class LIBDTKCORESHARED_EXPORT FunctionCallProxy : public QObject
22{
23 Q_OBJECT
24public:
25 explicit FunctionCallProxy(QThread *thread);
26
27 static void proxyCall(QSemaphore *s, QThread *thread, QObject *target, FunctionType fun);
28
29Q_SIGNALS:
30 void callInLiveThread(QSemaphore *s, QPointer<QObject> target, FunctionType *func);
31};
32
33template <typename ReturnType>
34class LIBDTKCORESHARED_EXPORT _TMP
35{
36public:
37 inline static ReturnType runInThread(QSemaphore *s, QThread *thread, QObject *target, std::function<ReturnType()> fun)
38 {
39 ReturnType result;
40 FunctionType proxyFun = [&result, &fun] () {
41 result = fun();
42 };
43
44 FunctionCallProxy::proxyCall(s, thread, target, proxyFun);
45 return result;
46 }
47
48 template <typename T>
49 inline static typename std::enable_if<!std::is_base_of<QObject, T>::value, ReturnType>::type
50 runInThread(QSemaphore *s, QThread *thread, T *, std::function<ReturnType()> fun)
51 {
52 return runInThread(s, thread, static_cast<QObject*>(nullptr), fun);
53 }
54};
55template <>
56class LIBDTKCORESHARED_EXPORT _TMP<void>
57{
58public:
59 inline static void runInThread(QSemaphore *s, QThread *thread, QObject *target, std::function<void()> fun)
60 {
61 FunctionCallProxy::proxyCall(s, thread, target, fun);
62 }
63
64 template <typename T>
65 inline static typename std::enable_if<!std::is_base_of<QObject, T>::value, void>::type
66 runInThread(QSemaphore *s, QThread *thread, T *, std::function<void()> fun)
67 {
68 return runInThread(s, thread, static_cast<QObject*>(nullptr), fun);
69 }
70};
71
72template <typename Fun, typename... Args>
73inline auto runInThread(QSemaphore *s, QThread *thread, QObject *target, Fun fun, Args&&... args) -> decltype(fun(args...))
74{
75 return _TMP<decltype(fun(args...))>::runInThread(s, thread, target, std::bind(fun, std::forward<Args>(args)...));
76}
77template <typename Fun, typename... Args>
78inline auto runInThread(QSemaphore *s, QThread *thread, Fun fun, Args&&... args) -> decltype(fun(args...))
79{
80 return runInThread(s, thread, nullptr, fun, std::forward<Args>(args)...);
81}
82template <typename Fun, typename... Args>
83inline typename QtPrivate::FunctionPointer<Fun>::ReturnType
84 runInThread(QSemaphore *s, QThread *thread, QObject *target, typename QtPrivate::FunctionPointer<Fun>::Object *obj, Fun fun, Args&&... args)
85{
86 return _TMP<typename QtPrivate::FunctionPointer<Fun>::ReturnType>::runInThread(s, thread, target, std::bind(fun, obj, std::forward<Args>(args)...));
87}
88template <typename Fun, typename... Args>
89inline typename QtPrivate::FunctionPointer<Fun>::ReturnType
90 runInThread(QSemaphore *s, QThread *thread, typename QtPrivate::FunctionPointer<Fun>::Object *obj, Fun fun, Args&&... args)
91{
92 return _TMP<typename QtPrivate::FunctionPointer<Fun>::ReturnType>::runInThread(s, thread, obj, std::bind(fun, obj, std::forward<Args>(args)...));
93}
94
95template <typename Fun, typename... Args>
96inline auto runInThread(QThread *thread, QObject *target, Fun fun, Args&&... args) -> decltype(fun(args...))
97{
98 QSemaphore s;
99
100 return runInThread(&s, thread, target, fun, std::forward<Args>(args)...);
101}
102template <typename Fun, typename... Args>
103inline auto runInThread(QThread *thread, Fun fun, Args&&... args) -> decltype(fun(args...))
104{
105 return runInThread(thread, nullptr, fun, std::forward<Args>(args)...);
106}
107template <typename T, typename Fun, typename... Args>
108inline typename QtPrivate::FunctionPointer<Fun>::ReturnType
109 runInThread(QThread *thread, T *target, typename QtPrivate::FunctionPointer<Fun>::Object *obj, Fun fun, Args&&... args)
110{
111 QSemaphore s;
112
113 return runInThread(&s, thread, target, obj, fun, std::forward<Args>(args)...);
114}
115
116template <typename Fun, typename... Args>
117inline typename QtPrivate::FunctionPointer<Fun>::ReturnType
118 runInThread(QThread *thread, typename QtPrivate::FunctionPointer<Fun>::Object *obj, Fun fun, Args&&... args)
119{
120 return runInThread(thread, obj, obj, fun, std::forward<Args>(args)...);
121}
122
123template <typename Fun, typename... Args>
124inline auto runInMainThread(QObject *target, Fun fun, Args&&... args) -> decltype(fun(args...))
125{
126 if (!QCoreApplication::instance()) {
127 return fun(std::forward<Args>(args)...);
128 }
129
130 return runInThread(QCoreApplication::instance()->thread(), target, fun, std::forward<Args>(args)...);
131}
132template <typename Fun, typename... Args>
133inline auto runInMainThread(Fun fun, Args&&... args) -> decltype(fun(args...))
134{
135 return runInMainThread(nullptr, fun, std::forward<Args>(args)...);
136}
137
138template <typename T, typename Fun, typename... Args>
139inline typename QtPrivate::FunctionPointer<Fun>::ReturnType
140 runInMainThread(T *target, typename QtPrivate::FunctionPointer<Fun>::Object *obj, Fun fun, Args&&... args)
141{
142 if (!QCoreApplication::instance()) {
143 return (obj->*fun)(std::forward<Args>(args)...);
144 }
145
146 return runInThread(QCoreApplication::instance()->thread(), target, obj, fun, std::forward<Args>(args)...);
147}
148template <typename Fun, typename... Args>
149inline typename QtPrivate::FunctionPointer<Fun>::ReturnType
150 runInMainThread(typename QtPrivate::FunctionPointer<Fun>::Object *obj, Fun fun, Args&&... args)
151{
152 return runInMainThread(obj, obj, fun, std::forward<Args>(args)...);
153}
154}
155
156DCORE_END_NAMESPACE
157
158#endif // DTHREADUTILS_H
Definition: dthreadutils.h:22
Definition: dthreadutils.h:35