/boost/lockfree/queue.hpp: error: static assertion failed: (boost::has_trivial_destructor<T>::value)
Asked Answered
E

3

6

I'm trying to substitute boost::lockfree::queue for std::queue in this file https://github.com/zaphoyd/websocketpp/blob/experimental/examples/broadcast_server/broadcast_server.cpp

I've added #include <boost/lockfree/queue.hpp>; changed line 130, std::queue<action> m_actions;, to boost::lockfree::queue<action> m_actions;; removed all lines having to do with locking; and changed line 103, m_actions.pop();, to m_actions.pop(a);.

I get these errors when I scons broadcast_server_lockfree in the project root after adding broadcast_server_lockfree = SConscript('#/broadcast_server_lockfree/SConscript',variant_dir = builddir + 'broadcast_server_lockfree',duplicate = 0) to the project root's SConstruct and using broadcast_server's SConstruct in the broadcast_server_lockfree directory:

root@server:~/websocketpp-experimental# scons broadcast_server_lockfree
scons: Reading SConscript files ...
C++11 build environment partially enabled
scons: done reading SConscript files.
scons: Building targets ...
scons: building associated VariantDir targets: build/release/broadcast_server_lockfree
g++ -o build/release/broadcast_server_lockfree/broadcast_server_lockfree.o -c -std=c++0x -Wall -Wcast-align -isystem /root/boost_1_53_0 -DNDEBUG -D_WEBSOCKETPP_CPP11_MEMORY_ -D_WEBSOCKETPP_CPP11_FUNCTIONAL_ -D_WEBSOCKETPP_CPP11_SYSTEM_ERROR_ -D_WEBSOCKETPP_CPP11_RANDOM_DEVICE_ -D_WEBSOCKETPP_NOEXCEPT_ -I. broadcast_server_lockfree/broadcast_server_lockfree.cpp
In file included from broadcast_server_lockfree/broadcast_server_lockfree.cpp:10:0:
/root/boost_1_53_0/boost/lockfree/queue.hpp: In instantiation of 'class boost::lockfree::queue<action>':
broadcast_server_lockfree/broadcast_server_lockfree.cpp:139:36:   required from here
/root/boost_1_53_0/boost/lockfree/queue.hpp:79:5: error: static assertion failed: (boost::has_trivial_destructor<T>::value)
/root/boost_1_53_0/boost/lockfree/queue.hpp:83:5: error: static assertion failed: (boost::has_trivial_assign<T>::value)
broadcast_server_lockfree/broadcast_server_lockfree.cpp: In member function 'void broadcast_server::process_messages()':
broadcast_server_lockfree/broadcast_server_lockfree.cpp:111:34: error: 'class boost::lockfree::queue<action>' has no member named 'front'
broadcast_server_lockfree/broadcast_server_lockfree.cpp:117:55: error: 'm_connection_lock' was not declared in this scope
broadcast_server_lockfree/broadcast_server_lockfree.cpp:120:55: error: 'm_connection_lock' was not declared in this scope
broadcast_server_lockfree/broadcast_server_lockfree.cpp:123:55: error: 'm_connection_lock' was not declared in this scope
In file included from broadcast_server_lockfree/broadcast_server_lockfree.cpp:10:0:
/root/boost_1_53_0/boost/lockfree/queue.hpp: In instantiation of 'boost::lockfree::queue<T, A0, A1, A2>::~queue() [with T = action; A0 = boost::parameter::void_; A1 = boost::parameter::void_; A2 = boost::parameter::void_]':
broadcast_server_lockfree/broadcast_server_lockfree.cpp:41:24:   required from here
/root/boost_1_53_0/boost/lockfree/queue.hpp:229:11: error: no matching function for call to 'action::action()'
/root/boost_1_53_0/boost/lockfree/queue.hpp:229:11: note: candidates are:
broadcast_server_lockfree/broadcast_server_lockfree.cpp:32:5: note: action::action(action_type, websocketpp::endpoint<websocketpp::connection<websocketpp::config::asio>, websocketpp::config::asio>::message_ptr)
broadcast_server_lockfree/broadcast_server_lockfree.cpp:32:5: note:   candidate expects 2 arguments, 0 provided
broadcast_server_lockfree/broadcast_server_lockfree.cpp:31:5: note: action::action(action_type, websocketpp::connection_hdl)
broadcast_server_lockfree/broadcast_server_lockfree.cpp:31:5: note:   candidate expects 2 arguments, 0 provided
broadcast_server_lockfree/broadcast_server_lockfree.cpp:30:8: note: action::action(const action&)
broadcast_server_lockfree/broadcast_server_lockfree.cpp:30:8: note:   candidate expects 1 argument, 0 provided
In file included from broadcast_server_lockfree/broadcast_server_lockfree.cpp:10:0:
/root/boost_1_53_0/boost/lockfree/queue.hpp: In instantiation of 'boost::lockfree::queue<T, A0, A1, A2>::node::node(boost::lockfree::queue<T, A0, A1, A2>::node::handle_type) [with T = action; A0 = boost::parameter::void_; A1 = boost::parameter::void_; A2 = boost::parameter::void_; boost::lockfree::queue<T, A0, A1, A2>::node::handle_type = boost::lockfree::queue<action>::node*]':
/root/boost_1_53_0/boost/lockfree/detail/freelist.hpp:82:13:   required from 'T* boost::lockfree::detail::freelist_stack<T, Alloc>::construct(const ArgumentType&) [with bool ThreadSafe = true; bool Bounded = false; ArgumentType = boost::lockfree::queue<action>::node*; T = boost::lockfree::queue<action>::node; Alloc = std::allocator<boost::lockfree::queue<action>::node>]'
/root/boost_1_53_0/boost/lockfree/queue.hpp:126:75:   required from 'void boost::lockfree::queue<T, A0, A1, A2>::initialize() [with T = action; A0 = boost::parameter::void_; A1 = boost::parameter::void_; A2 = boost::parameter::void_]'
/root/boost_1_53_0/boost/lockfree/queue.hpp:166:9:   required from 'boost::lockfree::queue<T, A0, A1, A2>::queue() [with T = action; A0 = boost::parameter::void_; A1 = boost::parameter::void_; A2 = boost::parameter::void_]'
broadcast_server_lockfree/broadcast_server_lockfree.cpp:41:24:   required from here
/root/boost_1_53_0/boost/lockfree/queue.hpp:109:52: error: no matching function for call to 'action::action()'
/root/boost_1_53_0/boost/lockfree/queue.hpp:109:52: note: candidates are:
broadcast_server_lockfree/broadcast_server_lockfree.cpp:32:5: note: action::action(action_type, websocketpp::endpoint<websocketpp::connection<websocketpp::config::asio>, websocketpp::config::asio>::message_ptr)
broadcast_server_lockfree/broadcast_server_lockfree.cpp:32:5: note:   candidate expects 2 arguments, 0 provided
broadcast_server_lockfree/broadcast_server_lockfree.cpp:31:5: note: action::action(action_type, websocketpp::connection_hdl)
broadcast_server_lockfree/broadcast_server_lockfree.cpp:31:5: note:   candidate expects 2 arguments, 0 provided
broadcast_server_lockfree/broadcast_server_lockfree.cpp:30:8: note: action::action(const action&)
broadcast_server_lockfree/broadcast_server_lockfree.cpp:30:8: note:   candidate expects 1 argument, 0 provided
scons: *** [build/release/broadcast_server_lockfree/broadcast_server_lockfree.o] Error 1
scons: building terminated because of errors.

I know next to nothing about c++, and searches on the error have yielded nothing (since I have no idea what I'm reading).

Here's the boost::lockfree::queue example if it helps. http://boost-sandbox.sourceforge.net/doc/html/lockfree/examples.html

Please show me how to correct this.

action

struct action {
    action(action_type t, connection_hdl h) : type(t), hdl(h) {}
    action(action_type t, server::message_ptr m) : type(t), msg(m) {}

    action_type type;
    websocketpp::connection_hdl hdl;
    server::message_ptr msg;
};
Ezra answered 18/3, 2013 at 1:7 Comment(0)
H
9

From the docs:

T must have a copy constructor, a trivial assignment operator, and a trivial destructor.

Thus your action class must look like the following:

class action
{
public:
    action(const action& rhs) { ... }
    //Implicitly defined destructor for itself and all member variables
    //Implicitly defined operator= for itself and all member variables

};

The static_asserts are complaining because your destructor and operator= are not implicitly defined by the compiler (or this is the case for at least one member variable of action).

Edit: I've had a quick look at the repo - I can't seem to find connection_hdl, and there is no message_ptr in template <typename endpoint> class server. Either way, one of websocketpp::connection_hdl hdl or server::message_ptr msg does not satisfy the above conditions. Just "dropping in" a lockfree queue instead of using a std::queue is likely a non-trivial task which will require a number of changes.

Hornbill answered 18/3, 2013 at 1:13 Comment(7)
Thank-you! Basically, I need to figure out how to convert action from a struct to class?Ezra
No. struct and class are the exact same thing in C++, except for default access specifiers (everything in a struct is default public, while everything in a class is default private). Without seeing action, there's no way of telling you how to fix this. However, utilizing boost generally requires a reasonable knowledge of C++ in the first place - you are going to struggle immensely otherwise.Hornbill
Thanks again! action's in the first link, line 29. I am more than fine with struggling through c++ to get all of the performance increases so long as there are great stack members like you willing to help. Without stack, I'd be condemned to something slower with less features like php ajax.Ezra
I've edited my post. This seems non-trivial. Unless someone is very familiar with this code, I doubt you'll get an answer telling you exactly what to do.Hornbill
This may be interesting: I'm trying to develop on windows for ease of development. Of course, I had to include websocketpp. What was strange was that I forgot to install boost. After including websocketpp but not boost, visual studio 2010 pro identified everything except connection_hdl. After I included and linked boost, vs10 recognized it. What do you think?Ezra
@Hornbill Thank you for this answer. It would appear std::function<void ()> fails this test as well. Does a workaround/wrapper design exist that allows me to "give" a class a trivial destructor?Volteface
@Volteface Nope. This post goes into some depth - #3899723 - but suffice to say, "trivial" is a recursive requirement - to be trivial x, all member variables must also be trivial x.Hornbill
G
2

This question has been answer well by the above posting. Here I will provide more examples. The fruitful discussion gave a lots of guidance please read them. The real matter is the requirement for the template type of the queue. For practicality, let's look at some real use cases.

namespace lkf=boost::lockfree;
vector<lkf::spsc_queue<pair<Fastq*,int>, lkf::capacity<100>>> datastore;
//lkf::queue<pair<char*,char*>, lkf::capacity<100>> pile1, pile2;  //failed assert
lkf::queue<pair<char*,char*>*, lkf::capacity<100>> pile1, pile2;

The first line in the code passed the compiler (because it is spac_queue), but the second line pair failed the compiler (due to boost::ASSERT):

/usr/local/include/boost/lockfree/queue.hpp:99:5: error: static assertion failed: (boost::has_trivial_assign<T>::value)
     BOOST_STATIC_ASSERT((boost::has_trivial_assign<T>::value));

After converting pair to pointer type (line 3), the compiler is happy.

Could be boost assertion needs to be updated? Converting to pointer is one quick trick, may not be the best.

The boost lockfree::queue has three Requirements:

  1. T must have a copy constructor
  2. T must have a trivial assignment operator
  3. T must have a trivial destructor

spsc_queue has two:

  1. T must have a default constructor
  2. T must be copyable
Gilbreath answered 29/3, 2019 at 21:4 Comment(6)
spsc_queue is a different type from queue. spsc_queue is a ring-buffer instead of some kind of linked list(?) that can optionally allocate more nodes. Anyway, presumably they just have different checks, whether they need those checks or not.Homolographic
But more importantly, the queue type doesn't need to be atomically copyable. pop doesn't read the data out of a node until after claiming it, and push doesn't add a node to the queue until after constructing it with the data. (Or for a ring-buffer, until after claiming that slot so no other writer will step on it.) I haven't checked boost's source specifically, but that's how normal lockless queues work in general. The queue entry management uses lockless atomic ops, but the data can be large as long as its trivially copyable.Homolographic
lockfree can be implemented with std::atomic_flagGilbreath
std::pair<char*,char*> is not trivially-copyable. godbolt.org/z/ly98DK shows that there is an operator= function that only inlines and optimizes away with optimization enabled. It does just copy the object representation, but that's not what C++ "trivially copyable" means, unfortunately. en.cppreference.com/w/cpp/utility/pair says that a pair is trivially destructible of both its member types are, but doesn't unfortunately guarantee that trivially copyable members result in a trivially copyable pair.Homolographic
I think you're misunderstanding lock freedom. If your only lock-free atomic type is atomic_flag, you can implement locks, and thus implement std::atomic<T> for arbitrary T, but it won't be lock-free, just atomic.Homolographic
lkf::queue works with a struct custom_pair{char *a,*b;};. godbolt.org/z/wQV5LU. Even adding a large array to the struct doesn't cause a problem, so it's clearly nothing to do with std::atomic<T>::is_always_lock_free. It's just the fact that the constructors and assignment operator are defaulted instead of explicit.Homolographic
C
0

I got this error when I used std::string for the queue item type.

boost::lockfree::queue<string>(10000)

As many good people have pointed out in the answers here and here, string is not allowed to be used for boost::lockfree::queue.

It does compiled with char *

boost::lockfree::queue<char*>(10000)

Crigger answered 24/11, 2020 at 10:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.