summaryrefslogtreecommitdiffhomepage
path: root/compat/run-in-thread.hpp
blob: c552c60024cb50108fd99c354ec13272634c7cb4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#pragma once

/* Copyright (c) 2016 Stanislaw Halik
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 */

#include <thread>
#include <condition_variable>
#include <utility>

#include <QObject>
#include <QThread>

namespace impl_run_in_thread {
struct semaphore final
{
    using lock_guard = std::unique_lock<std::mutex>;
    std::mutex mtx;
    std::condition_variable cvar;
    bool flag = false;

    semaphore() = default;

    void wait()
    {
        lock_guard guard(mtx);
        while (!flag)
            cvar.wait(guard);
    }

    void notify()
    {
        lock_guard guard(mtx);
        flag = true;
        cvar.notify_one();
    }
};
}

template<typename F>
void run_in_thread_sync(QObject* obj, F&& fun)
{
    if (obj->thread() == QThread::currentThread())
        return (void)fun();

    impl_run_in_thread::semaphore sem;

    {
        QObject src;
        QObject::connect(&src, &QObject::destroyed,
                         obj, [&] { fun(); sem.notify(); },
                         Qt::QueuedConnection);
    }

    sem.wait();
}

template<typename F>
void run_in_thread_async(QObject* obj, F&& fun)
{
    if (obj->thread() == QThread::currentThread())
        return (void)fun();

    QObject src;
    QObject::connect(&src, &QObject::destroyed, obj, std::forward<F>(fun), Qt::QueuedConnection);
}