fix async deadlock
This commit is contained in:
@ -19,7 +19,7 @@
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef ASYNCXX_H_
|
||||
# error "Do not include this header directly, include <async++.h> instead."
|
||||
#error "Do not include this header directly, include <async++.h> instead."
|
||||
#endif
|
||||
|
||||
namespace async {
|
||||
@ -37,20 +37,22 @@ namespace detail {
|
||||
|
||||
// Detect whether an object is a scheduler
|
||||
template<typename T, typename = decltype(std::declval<T>().schedule(std::declval<task_run_handle>()))>
|
||||
two& is_scheduler_helper(int);
|
||||
two &is_scheduler_helper(int);
|
||||
template<typename T>
|
||||
one& is_scheduler_helper(...);
|
||||
one &is_scheduler_helper(...);
|
||||
|
||||
template<typename T>
|
||||
struct is_scheduler: public std::integral_constant<bool, sizeof(is_scheduler_helper<T>(0)) - 1> {};
|
||||
struct is_scheduler : public std::integral_constant<bool, sizeof(is_scheduler_helper<T>(0)) - 1> {};
|
||||
|
||||
// Singleton scheduler classes
|
||||
class thread_scheduler_impl {
|
||||
public:
|
||||
LIBASYNC_EXPORT static void schedule(task_run_handle t);
|
||||
LIBASYNC_EXPORT static void schedule(task_run_handle t);
|
||||
};
|
||||
|
||||
class inline_scheduler_impl {
|
||||
public:
|
||||
static void schedule(task_run_handle t);
|
||||
static void schedule(task_run_handle t);
|
||||
};
|
||||
|
||||
// Reference counted pointer to task data
|
||||
@ -59,93 +61,98 @@ typedef ref_count_ptr<task_base> task_ptr;
|
||||
|
||||
// Helper function to schedule a task using a scheduler
|
||||
template<typename Sched>
|
||||
void schedule_task(Sched& sched, task_ptr t);
|
||||
void schedule_task(Sched &sched, task_ptr t);
|
||||
|
||||
// Wait for the given task to finish. This will call the wait handler currently
|
||||
// active for this thread, which causes the thread to sleep by default.
|
||||
LIBASYNC_EXPORT void wait_for_task(task_base* wait_task);
|
||||
#ifndef LIBASYNC_CUSTOM_WAIT_FOR_TASK
|
||||
LIBASYNC_EXPORT void wait_for_task(task_base *wait_task);
|
||||
#endif
|
||||
|
||||
// Forward-declaration for data used by threadpool_scheduler
|
||||
struct threadpool_data;
|
||||
|
||||
} // namespace detail
|
||||
}// namespace detail
|
||||
|
||||
// Run a task in the current thread as soon as it is scheduled
|
||||
inline detail::inline_scheduler_impl& inline_scheduler()
|
||||
inline detail::inline_scheduler_impl &
|
||||
inline_scheduler()
|
||||
{
|
||||
static detail::inline_scheduler_impl instance;
|
||||
return instance;
|
||||
static detail::inline_scheduler_impl instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
// Run a task in a separate thread. Note that this scheduler does not wait for
|
||||
// threads to finish at process exit. You must ensure that all threads finish
|
||||
// before ending the process.
|
||||
inline detail::thread_scheduler_impl& thread_scheduler()
|
||||
inline detail::thread_scheduler_impl &
|
||||
thread_scheduler()
|
||||
{
|
||||
static detail::thread_scheduler_impl instance;
|
||||
return instance;
|
||||
static detail::thread_scheduler_impl instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
// 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.
|
||||
LIBASYNC_EXPORT threadpool_scheduler& default_threadpool_scheduler();
|
||||
LIBASYNC_EXPORT threadpool_scheduler &default_threadpool_scheduler();
|
||||
|
||||
// Default scheduler that is used when one isn't specified. This defaults to
|
||||
// default_threadpool_scheduler(), but can be overriden by defining
|
||||
// LIBASYNC_CUSTOM_DEFAULT_SCHEDULER before including async++.h. Keep in mind
|
||||
// that in that case async::default_scheduler should be declared before
|
||||
// including async++.h.
|
||||
|
||||
#ifndef LIBASYNC_CUSTOM_DEFAULT_SCHEDULER
|
||||
inline threadpool_scheduler& default_scheduler()
|
||||
inline threadpool_scheduler &
|
||||
default_scheduler()
|
||||
{
|
||||
return default_threadpool_scheduler();
|
||||
return default_threadpool_scheduler();
|
||||
}
|
||||
#endif
|
||||
|
||||
// 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 {
|
||||
struct internal_data;
|
||||
std::unique_ptr<internal_data> impl;
|
||||
struct internal_data;
|
||||
std::unique_ptr<internal_data> impl;
|
||||
|
||||
public:
|
||||
LIBASYNC_EXPORT fifo_scheduler();
|
||||
LIBASYNC_EXPORT ~fifo_scheduler();
|
||||
LIBASYNC_EXPORT fifo_scheduler();
|
||||
LIBASYNC_EXPORT ~fifo_scheduler();
|
||||
|
||||
// Add a task to the queue
|
||||
LIBASYNC_EXPORT void schedule(task_run_handle t);
|
||||
// Add a task to the queue
|
||||
LIBASYNC_EXPORT void schedule(task_run_handle t);
|
||||
|
||||
// Try running one task from the queue. Returns false if the queue was empty.
|
||||
LIBASYNC_EXPORT bool try_run_one_task();
|
||||
// Try running one task from the queue. Returns false if the queue was empty.
|
||||
LIBASYNC_EXPORT bool try_run_one_task();
|
||||
|
||||
// Run all tasks in the queue
|
||||
LIBASYNC_EXPORT void run_all_tasks();
|
||||
// Run all tasks in the queue
|
||||
LIBASYNC_EXPORT 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 {
|
||||
std::unique_ptr<detail::threadpool_data> impl;
|
||||
std::unique_ptr<detail::threadpool_data> impl;
|
||||
|
||||
public:
|
||||
LIBASYNC_EXPORT threadpool_scheduler(threadpool_scheduler&& other);
|
||||
LIBASYNC_EXPORT threadpool_scheduler(threadpool_scheduler &&other);
|
||||
|
||||
// Create a thread pool with the given number of threads
|
||||
LIBASYNC_EXPORT threadpool_scheduler(std::size_t num_threads);
|
||||
// Create a thread pool with the given number of threads
|
||||
LIBASYNC_EXPORT threadpool_scheduler(std::size_t num_threads);
|
||||
|
||||
// Create a thread pool with the given number of threads. Call `prerun`
|
||||
// Create a thread pool with the given number of threads. Call `prerun`
|
||||
// function before execution loop and `postrun` after.
|
||||
LIBASYNC_EXPORT threadpool_scheduler(std::size_t num_threads,
|
||||
std::function<void()>&& prerun_,
|
||||
std::function<void()>&& postrun_);
|
||||
LIBASYNC_EXPORT
|
||||
threadpool_scheduler(std::size_t num_threads, std::function<void()> &&prerun_, std::function<void()> &&postrun_);
|
||||
|
||||
// Destroy the thread pool, tasks that haven't been started are dropped
|
||||
LIBASYNC_EXPORT ~threadpool_scheduler();
|
||||
// Destroy the thread pool, tasks that haven't been started are dropped
|
||||
LIBASYNC_EXPORT ~threadpool_scheduler();
|
||||
|
||||
// Schedule a task to be run in the thread pool
|
||||
LIBASYNC_EXPORT void schedule(task_run_handle t);
|
||||
// Schedule a task to be run in the thread pool
|
||||
LIBASYNC_EXPORT void schedule(task_run_handle t);
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
@ -153,5 +160,5 @@ namespace detail {
|
||||
// Work-around for Intel compiler handling decltype poorly in function returns
|
||||
typedef std::remove_reference<decltype(::async::default_scheduler())>::type default_scheduler_type;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace async
|
||||
}// namespace detail
|
||||
}// namespace async
|
||||
|
Reference in New Issue
Block a user