Boost :: lockfree :: queue of functions?
I would like to create simple boost::lockfree::queue
functions that take no arguments and do not return values.
It appears to boost::lockfree::queue
require the element type to be trivially assignable and destructible, a requirement that boost::function<void ()>
is unfortunately not met.
In the spirit of this StackOverflow question, I'm trying to achieve this with boost::lockfree::queue
simple function pointers:
boost::lockfree::queue<void (*)()> queue;
Can I push boost::function<void ()>
to this queue? If so, how?
source to share
Can I push
boost::function<void()>
to this queue?
Directly, since it boost::function<void()>
is a super-heavy type erasable wrapper that implicitly converts to a function pointer and also stores some data.
If you want a trivially assignable trivially destructible type that can refer to any function object, you can implement a class function_view
that points to some function object without owning it. If you are careful with the time-to-live and ensure that it function_view
always points to "live objects", you can safely store instances of this in your queue.
Conceptually, function_view
a pair of pointers. I have an implementation in "passing functions to functions , which I am pasting below:"
template <typename TReturn, typename... TArgs>
class function_view<TReturn(TArgs...)> final
{
private:
using signature_type = TReturn(void*, TArgs...);
void* _ptr;
TReturn (*_erased_fn)(void*, TArgs...);
public:
template <typename T, typename = std::enable_if_t<
std::is_callable<T&(TArgs...)>{} &&
!std::is_same<std::decay_t<T>, function_view>{}>>
function_view(T&& x) noexcept : _ptr{(void*)std::addressof(x)}
{
_erased_fn = [](void* ptr, TArgs... xs) -> TReturn {
return (*reinterpret_cast<std::add_pointer_t<T>>(ptr))(
std::forward<TArgs>(xs)...);
};
}
decltype(auto) operator()(TArgs... xs) const
noexcept(noexcept(_erased_fn(_ptr, std::forward<TArgs>(xs)...)))
{
return _erased_fn(_ptr, std::forward<TArgs>(xs)...);
}
};
This class passes the following tests:
using type = function_view<void()>;
static_assert(is_trivially_assignable<type, type>{});
static_assert(is_trivially_destructible<type>{});
source to share
no, but you can use dynamic memory allocation + type erasure for this reason:
struct callback_back{
virtual void execute() = 0;
~callback_base() = default;
};
template<class F>
class callback{
private:
F m_function;
public:
callback(F&& function) : m_function(std::forward<F>(function)){}
virtual void execute() {
m_function();
}
}
template<class F>
std::unique_ptr<callback_base> make_callback(F&& f){
return std::unique_ptr<callback_base>(
new callback<F>(std::forward<F>(f));
);
}
use callback_base
as non-switchable type (aka boost::lockfree::queue<std::unique_ptr<callback_base>>
).
source to share
The only way I have found so far is to make a raw pointer to a function object
boost::lockfree::queue<std::function<void(void)> *> tasks_; // the queue
// let f = stack allocated std::function<T(T)> instance
tasks_.push(new std::function<void(void)>(f));
The problem here is when it is safe to delete this instance.
source to share