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线程初始化的静态对象