Skip to content

Commit

Permalink
Avoid using util::function for thread function wrappers
Browse files Browse the repository at this point in the history
Currently, the non-plain versions of the register_work/register_thread functions
make use of util::function. This leads due unnecessary dynamic memory allocation
since the potential for util::function using the small object optimization is
limited.
  • Loading branch information
Thomas Heller committed Jan 19, 2018
1 parent 57730a9 commit 19414ab
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 174 deletions.
154 changes: 115 additions & 39 deletions hpx/runtime/threads/thread_helpers.hpp
@@ -1,4 +1,5 @@
// Copyright (c) 2007-2015 Hartmut Kaiser
// Copyright (c) 2018 Thomas Heller
// Copyright (c) 2011 Bryce Lelbach
// Copyright (c) 2008-2009 Chirag Dekate, Anshul Tandon
//
Expand All @@ -17,7 +18,9 @@
#include <hpx/runtime/threads/thread_data_fwd.hpp>
#include <hpx/runtime/threads/thread_enums.hpp>
#include <hpx/util_fwd.hpp>
#include <hpx/util/bind.hpp>
#include <hpx/util/unique_function.hpp>
#include <hpx/util/register_locks.hpp>
#include <hpx/util/steady_clock.hpp>
#include <hpx/util/thread_description.hpp>

Expand Down Expand Up @@ -757,6 +760,19 @@ namespace hpx { namespace applier
threads::thread_stacksize stacksize = threads::thread_stacksize_default,
error_code& ec = throws);

///////////////////////////////////////////////////////////////////////////
/// \brief Create a new \a thread using the given data.
///
/// \note This function is completely equivalent to the first overload
/// of threads#register_thread_plain above, except that part of the
/// parameters are passed as members of the threads#thread_init_data
/// object.
///
HPX_API_EXPORT threads::thread_id_type register_thread_plain(
threads::thread_init_data& data,
threads::thread_state_enum initial_state = threads::pending,
bool run_now = true, error_code& ec = throws);

///////////////////////////////////////////////////////////////////////////
/// \brief Create a new \a thread using the given function as the work to
/// be executed.
Expand All @@ -770,15 +786,64 @@ namespace hpx { namespace applier
/// \note All other arguments are equivalent to those of the function
/// \a threads#register_thread_plain
///
HPX_API_EXPORT threads::thread_id_type register_thread(
util::unique_function_nonser<void(threads::thread_state_ex_enum)> && func,
namespace detail
{
template <typename F>
struct thread_function
{
typename std::decay<F>::type f;

inline threads::thread_result_type operator()(threads::thread_arg_type)
{
// execute the actual thread function
std::forward<F>(f)(threads::wait_signaled);

// Verify that there are no more registered locks for this
// OS-thread. This will throw if there are still any locks
// held.
util::force_error_on_lock();

return threads::thread_result_type(threads::terminated, nullptr);
}
};

template <typename F>
struct thread_function_nullary
{
typename std::decay<F>::type f;

inline threads::thread_result_type operator()(threads::thread_arg_type)
{
// execute the actual thread function
f();

// Verify that there are no more registered locks for this
// OS-thread. This will throw if there are still any locks
// held.
util::force_error_on_lock();

return threads::thread_result_type(threads::terminated, nullptr);
}
};
}

template <typename F>
threads::thread_id_type register_thread(
F && func,
util::thread_description const& description = util::thread_description(),
threads::thread_state_enum initial_state = threads::pending,
bool run_now = true,
threads::thread_priority priority = threads::thread_priority_normal,
std::size_t os_thread = std::size_t(-1),
threads::thread_stacksize stacksize = threads::thread_stacksize_default,
error_code& ec = throws);
error_code& ec = throws)
{
threads::thread_function_type thread_func(
detail::thread_function<F>{std::forward<F>(func)});
return register_thread_plain(std::move(thread_func),
description, initial_state, run_now, priority, os_thread, stacksize,
ec);
}

///////////////////////////////////////////////////////////////////////////
/// \brief Create a new \a thread using the given function as the work to
Expand All @@ -792,28 +857,23 @@ namespace hpx { namespace applier
/// \note All other arguments are equivalent to those of the function
/// \a threads#register_thread_plain
///
HPX_API_EXPORT threads::thread_id_type register_thread_nullary(
util::unique_function_nonser<void()> && func,
template <typename F>
threads::thread_id_type register_thread_nullary(
F && func,
util::thread_description const& description = util::thread_description(),
threads::thread_state_enum initial_state = threads::pending,
bool run_now = true,
threads::thread_priority priority = threads::thread_priority_normal,
std::size_t os_thread = std::size_t(-1),
threads::thread_stacksize stacksize = threads::thread_stacksize_default,
error_code& ec = throws);

///////////////////////////////////////////////////////////////////////////
/// \brief Create a new \a thread using the given data.
///
/// \note This function is completely equivalent to the first overload
/// of threads#register_thread_plain above, except that part of the
/// parameters are passed as members of the threads#thread_init_data
/// object.
///
HPX_API_EXPORT threads::thread_id_type register_thread_plain(
threads::thread_init_data& data,
threads::thread_state_enum initial_state = threads::pending,
bool run_now = true, error_code& ec = throws);
error_code& ec = throws)
{
threads::thread_function_type thread_func(
detail::thread_function_nullary<F>{std::forward<F>(func)});
return register_thread_plain(std::move(thread_func),
description, initial_state, run_now, priority, os_thread, stacksize,
ec);
}

///////////////////////////////////////////////////////////////////////////
/// \brief Create a new work item using the given function as the
Expand Down Expand Up @@ -873,6 +933,20 @@ namespace hpx { namespace applier
threads::thread_stacksize stacksize = threads::thread_stacksize_default,
error_code& ec = throws);

///////////////////////////////////////////////////////////////////////////
/// \brief Create a new work item using the given function as the
/// work to be executed.
///
/// \note This function is completely equivalent to the first overload
/// of threads#register_work_plain above, except that part of the
/// parameters are passed as members of the threads#thread_init_data
/// object.
///
HPX_API_EXPORT void register_work_plain(
threads::thread_init_data& data,
threads::thread_state_enum initial_state = threads::pending,
error_code& ec = throws);

///////////////////////////////////////////////////////////////////////////
/// \brief Create a new work item using the given function as the
/// work to be executed.
Expand All @@ -886,14 +960,22 @@ namespace hpx { namespace applier
/// \note All other arguments are equivalent to those of the function
/// \a threads#register_work_plain
///
HPX_API_EXPORT void register_work(
util::unique_function_nonser<void(threads::thread_state_ex_enum)> && func,
template <typename F>
void register_work(
F && func,
util::thread_description const& description = util::thread_description(),
threads::thread_state_enum initial_state = threads::pending,
threads::thread_priority priority = threads::thread_priority_normal,
std::size_t os_thread = std::size_t(-1),
threads::thread_stacksize stacksize = threads::thread_stacksize_default,
error_code& ec = throws);
error_code& ec = throws)
{
threads::thread_function_type thread_func(
detail::thread_function<F>{std::forward<F>(func)});
return register_work_plain(std::move(thread_func),
description, 0, initial_state, priority, os_thread, stacksize,
ec);
}

///////////////////////////////////////////////////////////////////////////
/// \brief Create a new work item using the given function as the
Expand All @@ -907,28 +989,22 @@ namespace hpx { namespace applier
/// \note All other arguments are equivalent to those of the function
/// \a threads#register_work_plain
///
HPX_API_EXPORT void register_work_nullary(
util::unique_function_nonser<void()> && func,
template <typename F>
void register_work_nullary(
F && func,
util::thread_description const& description = util::thread_description(),
threads::thread_state_enum initial_state = threads::pending,
threads::thread_priority priority = threads::thread_priority_normal,
std::size_t os_thread = std::size_t(-1),
threads::thread_stacksize stacksize = threads::thread_stacksize_default,
error_code& ec = throws);

///////////////////////////////////////////////////////////////////////////
/// \brief Create a new work item using the given function as the
/// work to be executed.
///
/// \note This function is completely equivalent to the first overload
/// of threads#register_work_plain above, except that part of the
/// parameters are passed as members of the threads#thread_init_data
/// object.
///
HPX_API_EXPORT void register_work_plain(
threads::thread_init_data& data,
threads::thread_state_enum initial_state = threads::pending,
error_code& ec = throws);
error_code& ec = throws)
{
threads::thread_function_type thread_func(
detail::thread_function_nullary<F>{std::forward<F>(func)});
return register_work_plain(std::move(thread_func),
description, 0, initial_state, priority, os_thread, stacksize,
ec);
}
}}

///////////////////////////////////////////////////////////////////////////////
Expand Down
135 changes: 0 additions & 135 deletions src/runtime/applier/applier.cpp
Expand Up @@ -31,90 +31,6 @@
namespace hpx { namespace applier
{
///////////////////////////////////////////////////////////////////////////
static inline threads::thread_result_type thread_function(
util::unique_function_nonser<void(threads::thread_state_ex_enum)> func)
{
// execute the actual thread function
func(threads::wait_signaled);

// Verify that there are no more registered locks for this
// OS-thread. This will throw if there are still any locks
// held.
util::force_error_on_lock();

return threads::thread_result_type(threads::terminated, nullptr);
}

static inline threads::thread_result_type thread_function_nullary(
util::unique_function_nonser<void()> func)
{
// execute the actual thread function
func();

// Verify that there are no more registered locks for this
// OS-thread. This will throw if there are still any locks
// held.
util::force_error_on_lock();

return threads::thread_result_type(threads::terminated, nullptr);
}

///////////////////////////////////////////////////////////////////////////
threads::thread_id_type register_thread_nullary(
util::unique_function_nonser<void()> && func,
util::thread_description const& desc,
threads::thread_state_enum state, bool run_now,
threads::thread_priority priority, std::size_t os_thread,
threads::thread_stacksize stacksize, error_code& ec)
{
hpx::applier::applier* app = hpx::applier::get_applier_ptr();
if (nullptr == app)
{
HPX_THROWS_IF(ec, invalid_status,
"hpx::applier::register_thread_nullary",
"global applier object is not accessible");
return threads::invalid_thread_id;
}

util::thread_description d =
desc ? desc : util::thread_description(func, "register_thread_nullary");

threads::thread_init_data data(
util::bind(util::one_shot(&thread_function_nullary), std::move(func)),
d, 0, priority, os_thread, threads::get_stack_size(stacksize));

threads::thread_id_type id = threads::invalid_thread_id;
app->get_thread_manager().register_thread(data, id, state, run_now, ec);
return id;
}

threads::thread_id_type register_thread(
util::unique_function_nonser<void(threads::thread_state_ex_enum)> && func,
util::thread_description const& desc, threads::thread_state_enum state,
bool run_now, threads::thread_priority priority, std::size_t os_thread,
threads::thread_stacksize stacksize, error_code& ec)
{
hpx::applier::applier* app = hpx::applier::get_applier_ptr();
if (nullptr == app)
{
HPX_THROWS_IF(ec, invalid_status,
"hpx::applier::register_thread",
"global applier object is not accessible");
return threads::invalid_thread_id;
}

util::thread_description d =
desc ? desc : util::thread_description(func, "register_thread");

threads::thread_init_data data(
util::bind(util::one_shot(&thread_function), std::move(func)),
d, 0, priority, os_thread, threads::get_stack_size(stacksize));

threads::thread_id_type id = threads::invalid_thread_id;
app->get_thread_manager().register_thread(data, id, state, run_now, ec);
return id;
}

threads::thread_id_type register_thread_plain(
threads::thread_function_type && func,
util::thread_description const& desc, threads::thread_state_enum state,
Expand Down Expand Up @@ -160,57 +76,6 @@ namespace hpx { namespace applier
}

///////////////////////////////////////////////////////////////////////////
void register_work_nullary(
util::unique_function_nonser<void()> && func,
util::thread_description const& desc,
threads::thread_state_enum state, threads::thread_priority priority,
std::size_t os_thread, threads::thread_stacksize stacksize,
error_code& ec)
{
hpx::applier::applier* app = hpx::applier::get_applier_ptr();
if (nullptr == app)
{
HPX_THROWS_IF(ec, invalid_status,
"hpx::applier::register_work_nullary",
"global applier object is not accessible");
return;
}

util::thread_description d =
desc ? desc : util::thread_description(func, "register_work_nullary");

threads::thread_init_data data(
util::bind(util::one_shot(&thread_function_nullary), std::move(func)),
d, 0, priority, os_thread, threads::get_stack_size(stacksize));

app->get_thread_manager().register_work(data, state, ec);
}

void register_work(
util::unique_function_nonser<void(threads::thread_state_ex_enum)> && func,
util::thread_description const& desc, threads::thread_state_enum state,
threads::thread_priority priority, std::size_t os_thread,
threads::thread_stacksize stacksize, error_code& ec)
{
hpx::applier::applier* app = hpx::applier::get_applier_ptr();
if (nullptr == app)
{
HPX_THROWS_IF(ec, invalid_status,
"hpx::applier::register_work",
"global applier object is not accessible");
return;
}

util::thread_description d =
desc ? desc : util::thread_description(func, "register_work");

threads::thread_init_data data(
util::bind(util::one_shot(&thread_function), std::move(func)),
d, 0, priority, os_thread, threads::get_stack_size(stacksize));

app->get_thread_manager().register_work(data, state, ec);
}

void register_work_plain(
threads::thread_function_type && func,
util::thread_description const& desc, naming::address::address_type lva,
Expand Down

0 comments on commit 19414ab

Please sign in to comment.