-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathAsync.h
114 lines (95 loc) · 2.53 KB
/
Async.h
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//
// Copyright (C) Wojciech Jarosz <wjarosz@gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE.txt file.
//
#pragma once
#include <functional>
#include <future>
#include <chrono>
#include "Progress.h"
template <typename T>
class AsyncTask
{
public:
#if FORCE_SERIAL
static const auto policy = std::launch::deferred;
#else
static const auto policy = std::launch::async;
#endif
using TaskFunc = std::function<T(AtomicProgress & progress)>;
using NoProgressTaskFunc = std::function<T(void)>;
/*!
* Create an asyncronous task that can report back on its progress
* @param compute The function to execute asyncrhonously
*/
AsyncTask(TaskFunc compute)
: m_compute([compute](AtomicProgress & prog){T ret = compute(prog); prog.setDone(); return ret;}), m_progress(true)
{
}
/*!
* Create an asyncronous task without progress updates
* @param compute The function to execute asyncrhonously
*/
AsyncTask(NoProgressTaskFunc compute)
: m_compute([compute](AtomicProgress &){return compute();}), m_progress(false)
{
}
/*!
* Start the computation (if it hasn't already been started)
*/
void compute()
{
// start only if not done and not already started
if (!m_future.valid() && !m_ready)
m_future = std::async(policy, m_compute, std::ref(m_progress));
}
/*!
* Waits until the task has finished, and returns the result.
* The tasks return value is cached, so get can be called multiple times.
*
* @return The result of the computation
*/
T & get()
{
if (m_ready)
return m_value;
m_value = m_future.valid() ? m_future.get() : m_compute(m_progress);
m_ready = true;
return m_value;
}
/*!
* Query the progress of the task.
*
* @return The percentage done, ranging from 0.f to 100.f,
* or -1 to indicate busy if the task doesn't report back progress
*/
float progress() const
{
return m_progress.progress();
}
void setProgress(float p)
{
m_progress.resetProgress(p);
}
/*!
* @return true if the computation has finished
*/
bool ready() const
{
if (m_ready)
return true;
if (!m_future.valid())
return false;
auto status = m_future.wait_for(std::chrono::seconds(0));
// predent that the computation is ready for deferred execution since we will compute it on-demand in
// get() anyway
return (status == std::future_status::ready || status == std::future_status::deferred);
}
private:
TaskFunc m_compute;
std::future<T> m_future;
T m_value;
AtomicProgress m_progress;
bool m_ready = false;
};