2017-06-11 7 views
3

Ich möchte eine einfache boost::lockfree::queue von Funktionen, die keine Argumente und keine Werte zurückgeben.boost :: lockfree :: Warteschlange der Funktionen?

Es scheint, dass boost::lockfree::queue verlangt, dass der Elementtyp trivial zuweisbar und zerstörbar ist, Anforderungen, die boost::function<void()> leider nicht erfüllen.

Im Geiste der https://stackoverflow.com/a/21406186/393756, versuche ich jetzt dies durch eine boost::lockfree::queue von einfachen Funktionszeiger zu erreichen:

boost::lockfree::queue<void (*)()> queue; 

Kann ich einen boost::function<void()> in dieser Warteschlange schieben? Wenn ja, wie?

Antwort

1

Kann ich einen boost::function<void()> in diese Warteschlange schieben?

Nicht direkt, wie boost::function<void()> ist ein Schwergewicht besitzender Typ-gelöschten Wrapper, die nicht implizit umwandelbar in einen Funktionszeiger und auch einige Daten gespeichert ist.

Wenn Sie eine trivialer zuweisbare eine trivialen-zerstörbare Art benötigen, die ein Funktionsobjekt verweisen kann, könnten Sie eine function_view Klasse implementieren, ohne es zu besitzen bis zu einem gewissen Funktionsobjekt verweist. Wenn Sie mit den Lebensdauern vorsichtig sind und sicherstellen, dass function_view immer auf "Live-Objekte" zeigt, können Sie Instanzen davon in Ihrer Warteschlange sicher speichern.

Konzeptionell function_view ist ein Paar Zeiger. Ich habe eine Implementierung in meinem "passing functions to functions" Artikel, die ich weiter unten einfügen bin:

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

Diese Klasse übergibt die folgenden Tests:

using type = function_view<void()>; 
static_assert(is_trivially_assignable<type, type>{}); 
static_assert(is_trivially_destructible<type>{}); 

live example on wandbox

+0

, aber dann müssen Sie sich sorgen, dass die Ansicht kein gültiges Objekt anzeigt. Das bedeutet, dass Sie die Lebensdauer der Funktion verwalten müssen. Es ist hart, wenn man über Threading spricht. Wie würdest du wissen, dass die Ansicht ihre Arbeit getan hat und du die Funktion löschen kannst? –

+0

@DavidHaim: es hängt vom Anwendungsfall des OP ab. Wenn die Ownership/Lifetime-Hierarchie unklar ist, ist ein 'shared_ptr' /' unique_ptr' besser geeignet. Aber wenn er einen "Elternbereich" hat, in dem alle Funktionen leben, oder eine Art "Manager", in dem er Funktionen speichern kann, ist eine Ansicht vielleicht besser/effizienter. –

+0

@VittorioRomeo Um Ihre Frage zu beantworten: In meinem Szenario gibt es keinen Manager, der die Funktionen besitzt. –

1

nicht, aber Sie können dynamische Speicher verwenden Zuordnung + Typ Löschen für diese Ursache:

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

Verwenden Sie callback_base als No-Except-Movable-Typ (alias boost::lockfree::queue<std::unique_ptr<callback_base>>).

+0

Beachten Sie, dass 'unique_ptr' nicht in einer' lockfree :: queue' gespeichert werden kann, da es nicht einfach zerstörbar ist: https://wandbox.org/permlink/1E6MFC2KVB7xtbN7 –

+0

ha. interessant. Nun, in diesem Fall kann man 'boost :: lockfree :: queue ' benutzen und die Queue in einen sehr dünnen Wrapper einpacken, der ein 'std :: unique_ptr' holt und zurückgibt. –

Verwandte Themen