-
Notifications
You must be signed in to change notification settings - Fork 201
API Reference
Amanieu d'Antras edited this page Feb 13, 2015
·
16 revisions
class task<Result> {
// Result type of the task
typedef Result result_type;
// Create an empty task object (operator bool returns false)
task();
// Movable but not copyable
task(const task&) = delete;
task(task&&);
task& operator=(const task&) = delete;
task& operator=(task&&);
// Destroy the task object. This detaches the task and does not wait for
// it to finish.
~task();
// Returns true if this task object contains a reference to a valid
// task. If this is not the case then all other functions throw a
// std::invalid_argument exception.
explicit operator bool() const;
// Waits for the task to complete and then retrieves the result of the
// task. If the task contains an exception then that exception is
// rethrown. The result is moved out of the task, and then the task is
// cleared (operator bool returns false).
Result get();
// Waits for the task to have finished executing
void wait() const;
// Returns whether the task has finished executing
bool ready() const;
// Returns whether the task was canceled due to an exception
bool canceled() const;
// Returns the std::exception_ptr associated with this task if it
// was canceled by an exception. This calls wait() internally.
std::exception_ptr get_exception() const;
// Register a continuation function to be run after this task and
// invalidate the task object. The function can take a parameter
// of Result or task<Result>, and will be scheduled with the
// given scheduler.
task<T> then(Func f); // T = result type of f
task<T> then(Sched& sched, Func f); // T = result type of f
// Turn this task object into a shared_task<T>. This will
// invalidate the current task object.
shared_task<Result> share();
};
// shared_task<T> is almost identical to task<T>, except:
// - shared_task<T> is copyable, copies all refer to the same task
// - shared_task<T> doesn't get invalidated on get() and then()
// - get() returns a const reference to the result
class shared_task<Result> {
typedef Result result_type;
shared_task();
shared_task(const shared_task&);
shared_task(shared_task&&);
shared_task& operator=(const shared_task&);
shared_task& operator=(shared_task&&);
~shared_task();
explicit operator bool() const;
void get() const; // If Result is void
Result& get() const; // If Result is a reference type
const Result& get() const; // Otherwise
void wait() const;
bool ready() const;
bool canceled() const;
std::exception_ptr get_exception() const;
task<T> then(Func f) const; // T = result type of f
task<T> then(Sched& sched, Func f) const; // T = result type of f
};
// Create a completed task containing a value
task<T> make_task(T value);
task<T&> make_task(std::reference_wrapper<T> value);
task<void> make_task();
// Create a canceled task containing an exception
task<T> make_exception_task<T>(std::exception_ptr except);
// Spawn a task to run the given function, optionally using the given
// scheduler instead of the default.
task<T> spawn(Func f); // T = result type of f
task<T> spawn(Sched& sched, Func f); // T = result type of f
class local_task<Func> {
typedef Result result_type;
// Local tasks can only be created using local_spawn()
local_task() = delete;
// Local tasks are non-movable and non-copyable
local_task(const local_task&) = delete;
local_task(local_task&&) = delete;
local_task& operator=(const local_task&) = delete;
local_task& operator=(local_task&&) = delete;
// The destructor implicitly waits for the task to finish
~local_task();
// Waits for the task to complete and then retrieves the result of the
// task. If the task contains an exception then that exception is
// rethrown. The result is moved out of the task.
void get(); // If Result is void
Result& get(); // If Result is a reference type
Result get(); // Otherwise
// Waits for the task to have finished executing
void wait() const;
// Returns whether the task has finished executing
bool ready() const;
};
// Spawn a local task to run the given function, optionally using the given
// scheduler instead of the default. Note that because local_task is
// non-movable, the result of this function must be captured using auto&&.
local_task<Func> local_spawn(Func f);
local_task<Func> local_spawn(Sched& sched, Func f);
struct abandoned_event_task {};
class event_task<Result> {
// Creates an event_task initialized with a new event
event_task();
// Movable but not copyable
event_task(const event_task&) = delete;
event_task(event_task&&);
event_task& operator=(const event_task&) = delete;
event_task& operator=(event_task&&);
// If a result has not been set, the event is canceled with an
// abandoned_event_task exception.
~event_task();
// Get a task associated with this event. This can only be called once.
task<Result> get_task();
// Set the value of the event. The event can only be set once.
bool set() const; // If Result is void
bool set(Result& r) const; // If Result is a reference type
bool set(Result&& r) const; // Otherwise
bool set(const Result& r) const; // Otherwise
// Cancel the event with an exception. The event can only be set once.
bool set_exception(std::exception_ptr except) const;
};
// Result type returned by when_any
struct when_any_result<Result> {
// Index of the task that completed first
std::size_t index;
// Vector or tuple of results
Result result;
};
// Return a task which is completed when any one of the given tasks is
// completed. The result will contain the index a task that completed
// and a list of all the tasks that were passed in. For the variadic
// form, the tasks are allowed to have different types.
task<when_any_result<std::tuple<task<T>/shared_task<T>...>>>
when_any(task<T>/shared_task<T>... tasks);
task<when_any_result<std::vector<task<T>/shared_task<T>>>>
when_any(Iter begin, Iter end);
task<when_any_result<std::vector<task<T>/shared_task<T>>>>
when_any(Range tasks);
// Return a task which is completed when all of the given tasks are
// completed. The result will contain a list of all the tasks that
// were passed in. For the variadic form, the tasks are allowed to
// have different types.
task<std::tuple<task<T>/shared_task<T>...>>
when_all(task<T>/shared_task<T>... tasks);
task<std::vector<task<T>/shared_task<T>>> when_all(Iter begin, Iter end);
task<std::vector<task<T>/shared_task<T>>> when_all(Range tasks);
// Exception thrown by cancel_current_task
struct task_canceled {};
// A cancellation token is just a boolean flag that indicates whether to
// cancel a set of task. It must be explicitly checked by tasks.
class cancellation_token {
// A token is initialized to the 'not canceled' state
cancellation_token();
// Tokens are non-movable and non-copyable
cancellation_token(const cancellation_token&) = delete;
cancellation_token(cancellation_token&&) = delete;
cancellation_token& operator=(const cancellation_token&) = delete;
cancellation_token& operator=(cancellation_token&&) = delete;
// Returns whether the token has been canceled
bool is_canceled() const;
// Sets the token to the canceled state
void cancel();
// Reset the token to a non-canceled state
void reset();
};
// Throws a task_canceled exception if the token is canceled
void interruption_point(const cancellation_token& token);
// Range object representing 2 iterators
class range<Iter> {
Iter begin() const;
Iter end() const;
};
// Create a range from 2 iterators
range<Iter> make_range(Iter begin, Iter end);
// Integer range between 2 integers
class int_range<T> {
class iterator;
iterator begin() const;
iterator end() const;
};
// Create an integer range
int_range<T> irange(T begin, T end);
// Partitioners which wrap a range and split it between threads. A
// partitioner is just a range with an additional split() function.
// A simple partitioner which splits until a grain size is reached. If a
// grain size is not specified, one is chosen automatically.
<detail> static_partitioner(Range&& range);
<detail> static_partitioner(Range&& range, size_t grain);
// A more advanced partitioner which initially divides the range into one
// chunk for each available thread. The range is split further if a chunk
// gets stolen by a different thread.
<detail> auto_partitioner(Range&& range);
// Convert a range to a partitioner. This is a utility function for
// implementing new parallel algorithms. If the argument is already a
//partitioner then it is simply passed on.
decltype(auto_partitioner(range)) to_partitioner(Range&& range);
Partitioner&& to_partitioner(Partitioner&& partitioner);
// Run a set of functions in parallel, optionally using a scheduler
void parallel_invoke(Func&&... funcs);
void parallel_invoke(scheduler& sched, Func&&... funcs);
// Run a function over a range in parallel. The range parameter can also be
// a partitioner to explicitly control how jobs are distributed to threads.
void parallel_for(Range&& range, const Func& func);
void parallel_for(scheduler& sched, Range&& range, const Func& func);
// Reduce a range in parallel. The range parameter can also be a partitioner
// to explicitly control how jobs are distributed to threads.
Result parallel_reduce(Range&& range, const Result& initial,
const ReduceFunc& reduce);
Result parallel_reduce(scheduler& sched, Range&& range,
const Result& initial, const ReduceFunc& reduce);
// Apply a function to a range and reduce it in parallel. The range
// parameter can also be a partitioner to explicitly control how jobs are
// distributed to threads.
Result parallel_map_reduce(Range&& range, const Result& initial,
const MapFunc& map, const ReduceFunc& reduce);
Result parallel_map_reduce(scheduler& sched, Range&& range,
const Result& initial, const MapFunc& map,
const ReduceFunc& reduce);
// Default scheduler used when a scheduler isn't explicitly specified.
// This can be overriden by setting the LIBASYNC_CUSTOM_DEFAULT_SCHEDULER
// preprocessor macro. By default this calls default_threadpool_scheduler().
<detail>& default_scheduler();
// Built-in thread pool scheduler with a size that is configurable from the
// LIBASYNC_NUM_THREADS environment variable. If that variable does not
// exist then the number of CPUs in the system is used instead.
threadpool_scheduler& default_threadpool_scheduler();
// Scheduler that runs tasks inline in the calling thread
<detail>& inline_scheduler();
// Scheduler that runs tasks in a new thread. Note that this does not wait
// for threads to finish on shutdown.
<detail>& thread_scheduler();
// Scheduler that holds a list of tasks which can then be explicitly
// executed by a thread. Both adding and running tasks are thread-safe
// operations.
class fifo_scheduler {
fifo_scheduler();
// Movable but not copyable
fifo_scheduler(const fifo_scheduler&) = delete;
fifo_scheduler(fifo_scheduler&&);
fifo_scheduler& operator=(const fifo_scheduler&) = delete;
fifo_scheduler& operator=(fifo_scheduler&&);
// Note that any remaining tasks are not executed
~fifo_scheduler();
// Add a task to the queue
void schedule(task_run_handle t);
// Try running one task from the queue. Returns false if the queue was
// empty.
bool try_run_one_task();
// Run all tasks in the queue
void run_all_tasks();
};
// Scheduler that runs tasks in a work-stealing thread pool of the given
// size. Note that destroying the thread pool before all tasks have
// completed may result in some tasks not being executed.
class threadpool_scheduler {
// Create a new thread pool with the given number of threads.
threadpool_scheduler(size_t num_threads);
// Movable but not copyable
threadpool_scheduler(const threadpool_scheduler&) = delete;
threadpool_scheduler(threadpool_scheduler&&);
threadpool_scheduler& operator=(const threadpool_scheduler&) = delete;
threadpool_scheduler& operator=(threadpool_scheduler&&);
// Any tasks that are currently executing are finished, but any tasks
// added after destruction has begun are not executed.
~threadpool_scheduler();
// Run a task on the thread pool
void scheduler(task_run_handle t);
};
// Improved version of std::hardware_concurrency:
// - It never returns 0, 1 is returned instead.
// - It is guaranteed to remain constant for the duration of the program.
std::size_t hardware_concurrency();
// Handle representing a task that needs to be run
class task_run_handle {
// Create an invalid handle
task_run_handle();
// Movable but not copyable
task_run_handle(const task_run_handle&) = delete;
task_run_handle(task_run_handle&&);
task_run_handle& operator=(const task_run_handle&) = delete;
task_run_handle& operator=(task_run_handle&&);
// Check if a handle is valid
explicit operator bool() const;
// Execute the task and invalidate the handle
void run();
// Same as before, but uses the given wait handler
void run_with_wait_handler(wait_handler handler)
// Convert to a void pointer and invalidate the handle
void* to_void_ptr();
// Convert a void pointer back to a task_run_handle
static task_run_handle from_void_ptr(void*);
};
// Handle to represent a task that needs to be waited for
class task_wait_handle {
// Create an invalid handle
task_wait_handle();
// Movable and copyable
task_wait_handle(const task_wait_handle&);
task_wait_handle(task_wait_handle&&);
task_wait_handle& operator=(const task_wait_handle&);
task_wait_handle& operator=(task_wait_handle&&);
// Check if a handle is valid
explicit operator bool() const;
// Check if the task has finished
bool ready() const;
// Queue a function to be executed when the task has finished executing.
void on_finish(Func&& func)
};
// Set the wait handler for the current thread. This is used to allow a
// thread to do useful work while waiting for a task to complete. This also
// returns the previously defined wait handler.
typedef void (*wait_handler)(task_wait_handle t);
wait_handler set_thread_wait_handler(wait_handler w);
// Exception thrown when a task_run_handle is destroyed without having
// run its task.
struct task_not_executed {};