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?

+3


source to share


3 answers


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>{});

      

live example in wandbox

+1


source


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>>

).

+1


source


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.

0


source







All Articles