Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cache aware queue for multiple producers-consumers #49

Closed

Conversation

hardened-steel
Copy link

I will try to make an intrusive version, if I understand how it should be implemented.
May need to change the interface of the container, and to make it richer.

@khizmax
Copy link
Owner

khizmax commented Jan 10, 2016

How to use this queue? Where is any test?
I suspect there are memory leaks, for exampe, for this case:

  1. Create queue
  2. push 1000 items
  3. Destruct queue

What is the meaning of accessor class? It doesn't manage any specific data, it just a wrapper around the queue's internals. For what?
Your desision to raise an exception in dequeue() if the queue is empty is debatable for me. The normal state of the queue is empty in many application, so I think the following signature
bool dequeue( value_type& destination )
is more appropriate for common queue implementation, since throwing an exception is rather heavy-weight operation.
Further, it is not obvious for me that accessor object creation is thread-safe. I think, there is a case in multi-threaded environment when accessor object can point to reclaimed head.

@hardened-steel
Copy link
Author

  1. Утечка памяти - исправил.
  2. accessor class - это класс через который происходит весь доступ к контейнеру. Должен быть у каждого потока. Создание accessor - не thread safe. Он нужен в силу специфики самого алгоритма. Что означает, что интерфейс этой очереди не может быть таким же как у остальных queue библиотеки.
  3. Непонятно как писать тест (в стиле библиотеки, и чтобы он вошел в сборку), много непонятных макросов.
  4. По поводу исключений, интерфейса у функций - со всем согласен, не сразу подсмотрел интерфейс у подобных контейнеров.
  5. Это нормально, что библиотека не собирается с тестами?

@khizmax
Copy link
Owner

khizmax commented Jan 25, 2016

Как я понимаю, это попытка реализовать вот этот интересный алгоритм: http://www.par.univie.ac.at/project/peppher/publications/Published/opodis10lfq.pdf
Этот алгоритм существенно зависит от реализации safe memory reclamation (SMR), описанной Gidenstam'ом и являющейся некой помесью Hazard Pointer (для защиты локальных ссылок) и reference counting (для защиты глобальных ссылок). Я в libcds отказался от поддержки этой схемы (в libcds это был cds::gc::HRC), начиная с версии 2.0, по следующим причинам:
i. Эта SMR не дает каких-либо преимуществ для структур данных, которые могут быть реализованы на чистой схеме Hazard Pointer. То есть он значительно медленнее (по крайней мере, в моей реализации).
ii. Мне не удалось заставить его стабильно работать. То есть он периодически падал.

Оригинальный алгоритм CAQueue существенно полагается на свойства Gidenstam SMR, в частности, на reference counting, и не может быть реализован в терминах защиты только локальных ссылок, то есть в терминах Hazard Pointer.
Но в реализации CAQueue я не вижу даже защиты локальных ссылок на блоки, то есть применения Hazard Pointer. Каким образом обеспечивается безопасность работы с блоком одного потока, когда другой поток может этот блок в любой момент удалить?.. Просто счетчика ссылок на блок здесь может быть недостаточно.
У меня по-прежнему есть подозрение, что в CAQueue идет утечка памяти: я не вижу, как удаляются опустошенные блоки. Вполне возможно, что в деструкторе они все удаляются, но это значит, что в процессе работы очереди идет неконтролируемый рост потребления памяти под уже ненужные блоки, и только в деструкторе очереди все удаляется.

Вполне допускаю, что вам удалось модифицировать оригинальный алгоритм и сделать его пригодным для использования вовсе без каких-то специальных схем вроде Hazard Pointer и т.п. Но это нужно доказать. Для меня доказательством будет прохождение всех multi-threaded тестов очередей.

Насчет accessor. IMO, это надуманный класс, делающий данную очередь несовместимой с интерфейсом других алгоритмов очередей. В оригинальной статье говорится о thread-local storage, именно так и надо этот алгоритм реализовывать. Так как C++11 STL не содержит абстракции TLS, можно взять реализацию boost - http://www.boost.org/doc/libs/1_60_0/doc/html/thread/thread_local_storage.html. Тогда все "детали реализации" в виде accessor уйдут внутрь методов enqueue/dequeue и CAQueue станет по интерфейсу совершенно такой же, как и остальные очереди в libcds. А это значит, что специальных тестов для неё не придется писать, следует просто подключить её в уже существующие.

И наконец
5) Это нормально, что библиотека не собирается с тестами?
Это не нормально. Возможно, я чем-то повредил существующую систему сборки, так как сейчас как раз перехожу на сборку cmake + последовательно перевожу тесты на gtest. Для точного выявления проблемы мне надо знать, чем вы собираете - cmake или старыми скриптами build.sh?

@hardened-steel
Copy link
Author

  1. Это действительно этот алгоритм. В моей реализации ссылки на блоки - это просто указатели с подсчетом ссылок, если кто-то держит ссылку - нода будет жива. Я не понял как в оригинале должны быть реализованы эти ссылки, от слова совсем.
  2. По поводу утечки, я еще не делал push своего изменения, по факту там опечатка в деструкторе.
  3. Удаление неиспользуемых блоков, таки происходит в время работы, а не только в деструкторе. Это видно в коде в статье, функция DeleteNode. В моей реализации - это деструктор node_ptr, он же указатель со счетчиком ссылок.
  4. Про accessor, вообще не понял. Я знаю про TLS в С++11, и я бы воспользовался просто кл.словом thread_local, но в таком случае, в программе можно будет пользоваться только одной такой очередью, т.е. это будет просто singlton. Класс accessor - это попытка сделать очередь независимой от глобальных переменных, т.е. можно сколько угодно их создавать.
  5. При сборке использую cmake. ОС - Linux, gcc 5.1 (точно не помню).

@khizmax
Copy link
Owner

khizmax commented Jan 25, 2016

  1. Я не понял как в оригинале должны быть реализованы эти ссылки. Вообще, эти методы описаны, например, здесь - http://www.cse.chalmers.se/~ptrianta/papers/gpst-ispan05.pdf, и они весьма нетривиальны.
  2. требует изучения. Зная схему Gidenstam'а, для меня вовсе не очевидно, что здесь прокатит такое упрощение.
  3. Accessor не нужен. Вместо него - boost::thread_specific_ptr, в котором хранятся те же данные, что в accessor'е, в виде структуры, и который не торчит наружу. В качестве примера см. cds/algo/flat_combining.h - там применяется boost::thread_specific_ptr.
    Тогда внешний интерфейс CAQueue становится тривиальным - enqueue() + dequeue(), - и пригодным для тестирования в libcds framework без дополнительных оберток.
  4. сегодня посмотрю, что там не так с cmake.

@khizmax
Copy link
Owner

khizmax commented Jan 25, 2016

подумав ещё, прихожу к выводу, что подход с accessor интересен, - не надо возиться с TLS, тем самым можно ожидать какой-то performance бонус.
Вот только тесты для этого подхода придется писать отдельные

@khizmax
Copy link
Owner

khizmax commented Jan 25, 2016

cmake без проблем собирает на master вместе с тестами

cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=DEBUG -DWITH_TESTS=ON
make

@hardened-steel
Copy link
Author

У меня не собирается:
In file included from /usr/local/include/boost/intrusive/bstree.hpp:38:0,
from /usr/local/include/boost/intrusive/avltree.hpp:24,
from /usr/local/include/boost/intrusive/avl_set.hpp:17,
from /home/motorhead/Документы/libcds/cds/intrusive/striped_set/boost_avl_set.h:34,
from /home/motorhead/Документы/libcds/tests/test-hdr/set/hdr_intrusive_refinable_hashset_avlset.cpp:32:
/usr/local/include/boost/intrusive/detail/tree_value_compare.hpp: In instantiation of ‘typename boost::move_detail::disable_if<boost::intrusive::tree_value_compare<Key, T, KeyCompare, KeyOfValue>::is_key, const Key&>::type boost::intrusive::tree_value_compare<Key, T, KeyCompare, KeyOfValue>::key_forward(const U&) const [with U = int; Key = set::IntrusiveStripedSetHdrTest::base_itemboost::intrusive::avl_set_base_hook< >; T = set::IntrusiveStripedSetHdrTest::base_itemboost::intrusive::avl_set_base_hook< >; KeyCompare = set::IntrusiveStripedSetHdrTest::lessset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< > >; KeyOfValue = boost::move_detail::identityset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< > >; typename boost::move_detail::disable_if<boost::intrusive::tree_value_compare<Key, T, KeyCompare, KeyOfValue>::is_key, const Key&>::type = const set::IntrusiveStripedSetHdrTest::base_itemboost::intrusive::avl_set_base_hook< >&]’:
/usr/local/include/boost/intrusive/detail/tree_value_compare.hpp:72:37: required from ‘bool boost::intrusive::tree_value_compare<Key, T, KeyCompare, KeyOfValue>::operator()(const KeyType&, const KeyType2&) [with KeyType = int; KeyType2 = set::IntrusiveStripedSetHdrTest::base_itemboost::intrusive::avl_set_base_hook< >; Key = set::IntrusiveStripedSetHdrTest::base_itemboost::intrusive::avl_set_base_hook< >; T = set::IntrusiveStripedSetHdrTest::base_itemboost::intrusive::avl_set_base_hook< >; KeyCompare = set::IntrusiveStripedSetHdrTest::lessset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< > >; KeyOfValue = boost::move_detail::identityset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< > >]’
/usr/local/include/boost/intrusive/detail/key_nodeptr_comp.hpp:88:27: required from ‘bool boost::intrusive::detail::key_nodeptr_comp<KeyTypeKeyCompare, ValueTraits, KeyOfValue>::operator()(const KeyType&, const KeyType2&) [with KeyType = int; KeyType2 = boost::intrusive::avltree_node<void*>; KeyTypeKeyCompare = boost::intrusive::tree_value_compareset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< >, set::IntrusiveStripedSetHdrTest::base_itemboost::intrusive::avl_set_base_hook< >, set::IntrusiveStripedSetHdrTest::lessset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< > >, boost::move_detail::identityset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< > > >; ValueTraits = boost::intrusive::bhtraitsset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< >, boost::intrusive::avltree_node_traits<void, false>, (boost::intrusive::link_mode_type)1u, boost::intrusive::dft_tag, 5u>; KeyOfValue = boost::move_detail::identityset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< > >]’
/usr/local/include/boost/intrusive/bstree_algorithms.hpp:750:31: required from ‘static boost::intrusive::bstree_algorithms::node_ptr boost::intrusive::bstree_algorithms::find(const const_node_ptr&, const KeyType&, KeyNodePtrCompare) [with KeyType = int; KeyNodePtrCompare = boost::intrusive::detail::key_nodeptr_compboost::intrusive::tree_value_compare<set::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< >, set::IntrusiveStripedSetHdrTest::base_itemboost::intrusive::avl_set_base_hook< >, set::IntrusiveStripedSetHdrTest::lessset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< > >, boost::move_detail::identityset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< > > >, boost::intrusive::bhtraitsset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< >, boost::intrusive::avltree_node_traits<void*, false>, (boost::intrusive::link_mode_type)1u, boost::intrusive::dft_tag, 5u>, boost::move_detail::identityset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< > > >; NodeTraits = boost::intrusive::avltree_node_traits<void*, false>; boost::intrusive::bstree_algorithms::node_ptr = boost::intrusive::avltree_node<void*>; boost::intrusive::bstree_algorithms::const_node_ptr = const boost::intrusive::avltree_node<void>]’
/usr/local/include/boost/intrusive/bstree.hpp:376:32: required from ‘boost::intrusive::bstbase2<ValueTraits, VoidOrKeyOfValue, VoidOrKeyComp, AlgoType, HeaderHolder>::iterator boost::intrusive::bstbase2<ValueTraits, VoidOrKeyOfValue, VoidOrKeyComp, AlgoType, HeaderHolder>::find(const KeyType&, KeyTypeKeyCompare) [with KeyType = int; KeyTypeKeyCompare = boost::intrusive::tree_value_compareset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< >, set::IntrusiveStripedSetHdrTest::base_itemboost::intrusive::avl_set_base_hook< >, set::IntrusiveStripedSetHdrTest::lessset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< > >, boost::move_detail::identityset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< > > >; ValueTraits = boost::intrusive::bhtraitsset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< >, boost::intrusive::avltree_node_traits<void
, false>, (boost::intrusive::link_mode_type)1u, boost::intrusive::dft_tag, 5u>; VoidOrKeyOfValue = void; VoidOrKeyComp = set::IntrusiveStripedSetHdrTest::lessset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< > >; boost::intrusive::algo_types AlgoType = (boost::intrusive::algo_types)6u; HeaderHolder = void; boost::intrusive::bstbase2<ValueTraits, VoidOrKeyOfValue, VoidOrKeyComp, AlgoType, HeaderHolder>::iterator = boost::intrusive::tree_iteratorboost::intrusive::bhtraits<set::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< >, boost::intrusive::avltree_node_traits<void*, false>, (boost::intrusive::link_mode_type)1u, boost::intrusive::dft_tag, 5u>, false>]’
/home/motorhead/Документы/libcds/cds/intrusive/striped_set/adapter.h:278:69: required from ‘cds::intrusive::striped_set::details::boost_intrusive_set_adapter::value_type* cds::intrusive::striped_set::details::boost_intrusive_set_adapter::erase(const Q&, Func) [with Q = int; Func = set::IntrusiveStripedSetHdrTest::erase_functor; Set = boost::intrusive::avl_setset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< >, boost::intrusive::compareset::IntrusiveStripedSetHdrTest::less<set::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< > > > >; cds::intrusive::striped_set::details::boost_intrusive_set_adapter::value_type = set::IntrusiveStripedSetHdrTest::base_itemboost::intrusive::avl_set_base_hook< >]’
/home/motorhead/Документы/libcds/cds/intrusive/striped_set.h:670:22: required from ‘cds::intrusive::StripedSet<Container, Options>::value_type* cds::intrusive::StripedSet<Container, Options>::erase(const Q&, Func) [with Q = int; Func = set::IntrusiveStripedSetHdrTest::erase_functor; Container = boost::intrusive::avl_setset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< >, boost::intrusive::compareset::IntrusiveStripedSetHdrTest::less<set::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< > > > >; Options = {cds::opt::hashset::IntrusiveStripedSetHdrTest::hash_int, cds::opt::resizing_policycds::intrusive::striped_set::single_bucket_size_threshold<0ul >, cds::opt::mutex_policy<cds::intrusive::striped_set::refinable<std::recursive_mutex, cds::backoff::yield, std::allocator > >}; cds::intrusive::StripedSet<Container, Options>::value_type = set::IntrusiveStripedSetHdrTest::base_itemboost::intrusive::avl_set_base_hook< >]’
/home/motorhead/Документы/libcds/tests/test-hdr/set/hdr_intrusive_striped_set.h:451:13: required from ‘void set::IntrusiveStripedSetHdrTest::test_with(Set&) [with Set = cds::intrusive::StripedSetboost::intrusive::avl_set<set::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< >, boost::intrusive::compareset::IntrusiveStripedSetHdrTest::less<set::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< > > > >, cds::opt::hashset::IntrusiveStripedSetHdrTest::hash_int, cds::opt::resizing_policycds::intrusive::striped_set::single_bucket_size_threshold<0ul >, cds::opt::mutex_policy<cds::intrusive::striped_set::refinable<std::recursive_mutex, cds::backoff::yield, std::allocator > > >]’
/home/motorhead/Документы/libcds/tests/test-hdr/set/hdr_intrusive_refinable_hashset_avlset.cpp:103:22: required from here
/usr/local/include/boost/intrusive/detail/tree_value_compare.hpp:64:26: error: no match for call to ‘(boost::move_detail::identityset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< > >) (const int&)’
{ return KeyOfValue()(key); }
^
In file included from /usr/local/include/boost/move/detail/type_traits.hpp:31:0,
from /usr/local/include/boost/intrusive/detail/mpl.hpp:26,
from /usr/local/include/boost/intrusive/pointer_traits.hpp:24,
from /usr/local/include/boost/intrusive/detail/uncast.hpp:25,
from /usr/local/include/boost/intrusive/detail/bstree_algorithms_base.hpp:24,
from /usr/local/include/boost/intrusive/bstree_algorithms.hpp:19,
from /usr/local/include/boost/intrusive/avltree_algorithms.hpp:25,
from /usr/local/include/boost/intrusive/detail/avltree_node.hpp:26,
from /usr/local/include/boost/intrusive/avl_set_hook.hpp:19,
from /usr/local/include/boost/intrusive/avltree.hpp:22,
from /usr/local/include/boost/intrusive/avl_set.hpp:17,
from /home/motorhead/Документы/libcds/cds/intrusive/striped_set/boost_avl_set.h:34,
from /home/motorhead/Документы/libcds/tests/test-hdr/set/hdr_intrusive_refinable_hashset_avlset.cpp:32:
/usr/local/include/boost/move/detail/meta_utils.hpp:223:14: note: candidate: boost::move_detail::identity::reference boost::move_detail::identity::operator()(boost::move_detail::identity::reference) [with T = set::IntrusiveStripedSetHdrTest::base_itemboost::intrusive::avl_set_base_hook< >; boost::move_detail::identity::reference = const set::IntrusiveStripedSetHdrTest::base_itemboost::intrusive::avl_set_base_hook< >&]
reference operator()(reference t)
^
/usr/local/include/boost/move/detail/meta_utils.hpp:223:14: note: no known conversion for argument 1 from ‘const int’ to ‘boost::move_detail::identityset::IntrusiveStripedSetHdrTest::base_item<boost::intrusive::avl_set_base_hook< > >::reference {aka const set::IntrusiveStripedSetHdrTest::base_itemboost::intrusive::avl_set_base_hook< >&}’
In file included from /usr/local/include/boost/intrusive/bstree.hpp:38:0,
from /usr/local/include/boost/intrusive/avltree.hpp:24,
from /usr/local/include/boost/intrusive/avl_set.hpp:17,
from /home/motorhead/Документы/libcds/cds/intrusive/striped_set/boost_avl_set.h:34,
from /home/motorhead/Документы/libcds/tests/test-hdr/set/hdr_intrusive_refinable_hashset_avlset.cpp:32:
/usr/local/include/boost/intrusive/detail/tree_value_compare.hpp: In instantiation of ‘typename boost::move_detail::disable_if<boost::intrusive::tree_value_compare<Key, T, KeyCompare, KeyOfValue>::is_key, const Key&>::type boost::intrusive::tree_value_compare<Key, T, KeyCompare, KeyOfValue>::key_forward(const U&) const [with U = int; Key = set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >; T = set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >; KeyCompare = set::IntrusiveStripedSetHdrTest::lessset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< > >; KeyOfValue = boost::move_detail::identityset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< > >; typename boost::move_detail::disable_if<boost::intrusive::tree_value_compare<Key, T, KeyCompare, KeyOfValue>::is_key, const Key&>::type = const set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >&]’:
/usr/local/include/boost/intrusive/detail/tree_value_compare.hpp:72:37: required from ‘bool boost::intrusive::tree_value_compare<Key, T, KeyCompare, KeyOfValue>::operator()(const KeyType&, const KeyType2&) [with KeyType = int; KeyType2 = set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >; Key = set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >; T = set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >; KeyCompare = set::IntrusiveStripedSetHdrTest::lessset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< > >; KeyOfValue = boost::move_detail::identityset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< > >]’
/usr/local/include/boost/intrusive/detail/key_nodeptr_comp.hpp:88:27: required from ‘bool boost::intrusive::detail::key_nodeptr_comp<KeyTypeKeyCompare, ValueTraits, KeyOfValue>::operator()(const KeyType&, const KeyType2&) [with KeyType = int; KeyType2 = boost::intrusive::avltree_node<void*>; KeyTypeKeyCompare = boost::intrusive::tree_value_compareset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< >, set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >, set::IntrusiveStripedSetHdrTest::lessset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< > >, boost::move_detail::identityset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< > > >; ValueTraits = boost::intrusive::mhtraitsset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< >, boost::intrusive::avl_set_member_hook<>, &set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >::hMember>; KeyOfValue = boost::move_detail::identityset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< > >]’
/usr/local/include/boost/intrusive/bstree_algorithms.hpp:750:31: required from ‘static boost::intrusive::bstree_algorithms::node_ptr boost::intrusive::bstree_algorithms::find(const const_node_ptr&, const KeyType&, KeyNodePtrCompare) [with KeyType = int; KeyNodePtrCompare = boost::intrusive::detail::key_nodeptr_compboost::intrusive::tree_value_compare<set::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< >, set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >, set::IntrusiveStripedSetHdrTest::lessset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< > >, boost::move_detail::identityset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< > > >, boost::intrusive::mhtraitsset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< >, boost::intrusive::avl_set_member_hook<>, &set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >::hMember>, boost::move_detail::identityset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< > > >; NodeTraits = boost::intrusive::avltree_node_traits<void
, false>; boost::intrusive::bstree_algorithms::node_ptr = boost::intrusive::avltree_node<void*>; boost::intrusive::bstree_algorithms::const_node_ptr = const boost::intrusive::avltree_node<void>]’
/usr/local/include/boost/intrusive/bstree.hpp:376:32: required from ‘boost::intrusive::bstbase2<ValueTraits, VoidOrKeyOfValue, VoidOrKeyComp, AlgoType, HeaderHolder>::iterator boost::intrusive::bstbase2<ValueTraits, VoidOrKeyOfValue, VoidOrKeyComp, AlgoType, HeaderHolder>::find(const KeyType&, KeyTypeKeyCompare) [with KeyType = int; KeyTypeKeyCompare = boost::intrusive::tree_value_compareset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< >, set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >, set::IntrusiveStripedSetHdrTest::lessset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< > >, boost::move_detail::identityset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< > > >; ValueTraits = boost::intrusive::mhtraitsset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< >, boost::intrusive::avl_set_member_hook<>, &set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >::hMember>; VoidOrKeyOfValue = void; VoidOrKeyComp = set::IntrusiveStripedSetHdrTest::lessset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< > >; boost::intrusive::algo_types AlgoType = (boost::intrusive::algo_types)6u; HeaderHolder = void; boost::intrusive::bstbase2<ValueTraits, VoidOrKeyOfValue, VoidOrKeyComp, AlgoType, HeaderHolder>::iterator = boost::intrusive::tree_iteratorboost::intrusive::mhtraits<set::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< >, boost::intrusive::avl_set_member_hook<>, &set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >::hMember>, false>]’
/home/motorhead/Документы/libcds/cds/intrusive/striped_set/adapter.h:278:69: required from ‘cds::intrusive::striped_set::details::boost_intrusive_set_adapter::value_type
cds::intrusive::striped_set::details::boost_intrusive_set_adapter::erase(const Q&, Func) [with Q = int; Func = set::IntrusiveStripedSetHdrTest::erase_functor; Set = boost::intrusive::avl_setset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< >, boost::intrusive::member_hookset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< >, boost::intrusive::avl_set_member_hook<>, &set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >::hMember>, boost::intrusive::compareset::IntrusiveStripedSetHdrTest::less<set::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< > > > >; cds::intrusive::striped_set::details::boost_intrusive_set_adapter::value_type = set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >]’
/home/motorhead/Документы/libcds/cds/intrusive/striped_set.h:670:22: required from ‘cds::intrusive::StripedSet<Container, Options>::value_type* cds::intrusive::StripedSet<Container, Options>::erase(const Q&, Func) [with Q = int; Func = set::IntrusiveStripedSetHdrTest::erase_functor; Container = boost::intrusive::avl_setset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< >, boost::intrusive::member_hookset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< >, boost::intrusive::avl_set_member_hook<>, &set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >::hMember>, boost::intrusive::compareset::IntrusiveStripedSetHdrTest::less<set::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< > > > >; Options = {cds::opt::hashset::IntrusiveStripedSetHdrTest::hash_int, cds::opt::mutex_policy<cds::intrusive::striped_set::refinable<std::recursive_mutex, cds::backoff::yield, std::allocator > >, cds::opt::resizing_policycds::intrusive::striped_set::single_bucket_size_threshold<0ul >}; cds::intrusive::StripedSet<Container, Options>::value_type = set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >]’
/home/motorhead/Документы/libcds/tests/test-hdr/set/hdr_intrusive_striped_set.h:451:13: required from ‘void set::IntrusiveStripedSetHdrTest::test_with(Set&) [with Set = cds::intrusive::StripedSetboost::intrusive::avl_set<set::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< >, boost::intrusive::member_hookset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< >, boost::intrusive::avl_set_member_hook<>, &set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >::hMember>, boost::intrusive::compareset::IntrusiveStripedSetHdrTest::less<set::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< > > > >, cds::opt::hashset::IntrusiveStripedSetHdrTest::hash_int, cds::opt::mutex_policy<cds::intrusive::striped_set::refinable<std::recursive_mutex, cds::backoff::yield, std::allocator > >, cds::opt::resizing_policycds::intrusive::striped_set::single_bucket_size_threshold<0ul > >]’
/home/motorhead/Документы/libcds/tests/test-hdr/set/hdr_intrusive_refinable_hashset_avlset.cpp:154:22: required from here
/usr/local/include/boost/intrusive/detail/tree_value_compare.hpp:64:26: error: no match for call to ‘(boost::move_detail::identityset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< > >) (const int&)’
{ return KeyOfValue()(key); }
^
In file included from /usr/local/include/boost/move/detail/type_traits.hpp:31:0,
from /usr/local/include/boost/intrusive/detail/mpl.hpp:26,
from /usr/local/include/boost/intrusive/pointer_traits.hpp:24,
from /usr/local/include/boost/intrusive/detail/uncast.hpp:25,
from /usr/local/include/boost/intrusive/detail/bstree_algorithms_base.hpp:24,
from /usr/local/include/boost/intrusive/bstree_algorithms.hpp:19,
from /usr/local/include/boost/intrusive/avltree_algorithms.hpp:25,
from /usr/local/include/boost/intrusive/detail/avltree_node.hpp:26,
from /usr/local/include/boost/intrusive/avl_set_hook.hpp:19,
from /usr/local/include/boost/intrusive/avltree.hpp:22,
from /usr/local/include/boost/intrusive/avl_set.hpp:17,
from /home/motorhead/Документы/libcds/cds/intrusive/striped_set/boost_avl_set.h:34,
from /home/motorhead/Документы/libcds/tests/test-hdr/set/hdr_intrusive_refinable_hashset_avlset.cpp:32:
/usr/local/include/boost/move/detail/meta_utils.hpp:223:14: note: candidate: boost::move_detail::identity::reference boost::move_detail::identity::operator()(boost::move_detail::identity::reference) [with T = set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >; boost::move_detail::identity::reference = const set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >&]
reference operator()(reference t)
^
/usr/local/include/boost/move/detail/meta_utils.hpp:223:14: note: no known conversion for argument 1 from ‘const int’ to ‘boost::move_detail::identityset::IntrusiveStripedSetHdrTest::member_item<boost::intrusive::avl_set_member_hook< > >::reference {aka const set::IntrusiveStripedSetHdrTest::member_itemboost::intrusive::avl_set_member_hook< >&}’
make[2]: *** [tests/test-hdr/CMakeFiles/test-hdr.dir/set/hdr_intrusive_refinable_hashset_avlset.cpp.o] Ошибка 1
make[1]: *** [tests/test-hdr/CMakeFiles/test-hdr.dir/all] Ошибка 2
make: *** [all] Ошибка 2

@khizmax
Copy link
Owner

khizmax commented Jan 26, 2016

Какая версия boost?

@hardened-steel
Copy link
Author

1.59

@khizmax
Copy link
Owner

khizmax commented Jan 26, 2016

Это бага в boost 1.59.
Workaround закоммичен 24a9e5e

@hardened-steel
Copy link
Author

Реализовал вариант с boost::thread_specific_ptr, теперь интерфейс совместимый, добавил тесты

@khizmax
Copy link
Owner

khizmax commented Feb 3, 2016

Good work!

Осталось две небольшие мелочи:

  1. Массовая утечка памяти
  2. Откомметировать код: все public-члены должны иметь doxygen-комментарии + коммент на сам класс.

Memory leaks:
Queue_ReaderWriter::CacheAwareQueue_default
reader count=4 writer count=4 item count=100000...
Все элементы (400 000) не освобождаются:

==2657==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 1600000 byte(s) in 100000 object(s) allocated from:
#0 0x7f9ff2018c4a in operator new(unsigned long) ../../../../gcc-5.3.0/libsanitizer/asan/asan_new_delete.cc:60
#1 0x7f9ff356ca4e in allocate /home/khizmax/bin/gcc-5.3/include/c++/5.3.0/ext/new_allocator.h:104
#2 0x7f9ff356ca4e in New<queue::(anonymous namespace)::Value> ../cds/details/allocator.h:73
#3 0x7f9ff356ca4e in enqueue ../cds/container/cache_aware_queue.h:214
#4 0x7f9ff356ca4e in push ../cds/container/cache_aware_queue.h:231
#5 0x7f9ff356ca4e in test ../tests/unit/queue/queue_reader_writer.cpp:105
#6 0x7f9ff38b5810 in CppUnitMini::TestThread::run() ../tests/cppunit/thread.cpp:53
#7 0x7f9ff38b59da in CppUnitMini::TestThread::threadEntryPoint(CppUnitMini::TestThread_) ../tests/cppunit/thread.cpp:39
#8 0x7f9ff38b5c0b in void boost::_bi::list1<boost::_bi::valueCppUnitMini::TestThread_ >::operator()<void ()(CppUnitMini::TestThread), boost::bi::list0>(boost::bi::type, void (&)(CppUnitMini::TestThread), boost::_bi::list0&, int) /home/khizmax/works/lib/boost_1_58_0/boost/bind/bind.hpp:253
#9 0x7f9ff38b5c0b in boost::_bi::bind_t<void, void ()(CppUnitMini::TestThread), boost::_bi::list1<boost::_bi::valueCppUnitMini::TestThread* > >::operator()() /home/khizmax/works/lib/boost_1_58_0/boost/bind/bind.hpp:893
#10 0x7f9ff38b5c0b in boost::detail::thread_data<boost::_bi::bind_t<void, void ()(CppUnitMini::TestThread), boost::_bi::list1<boost::_bi::valueCppUnitMini::TestThread* > > >::run() /home/khizmax/works/lib/boost_1_58_0/boost/thread/detail/thread.hpp:116
#11 0x7f9ff38c7a2a in thread_proxy (/home/khizmax/works/cds-2-linux/bin/gcc-5-asan-amd64-linux-64/cdsu-queue+0x7b4a2a)

Direct leak of 1600000 byte(s) in 100000 object(s) allocated from:
#0 0x7f9ff2018c4a in operator new(unsigned long) ../../../../gcc-5.3.0/libsanitizer/asan/asan_new_delete.cc:60
#1 0x7f9ff356d6fa in allocate /home/khizmax/bin/gcc-5.3/include/c++/5.3.0/ext/new_allocator.h:104
#2 0x7f9ff356d6fa in New<queue::(anonymous namespace)::Value> ../cds/details/allocator.h:73
#3 0x7f9ff356d6fa in enqueue ../cds/container/cache_aware_queue.h:214
#4 0x7f9ff356d6fa in push ../cds/container/cache_aware_queue.h:231
#5 0x7f9ff356d6fa in test ../tests/unit/queue/queue_reader_writer.cpp:105
#6 0x7f9ff38b5810 in CppUnitMini::TestThread::run() ../tests/cppunit/thread.cpp:53
#7 0x7f9ff38b59da in CppUnitMini::TestThread::threadEntryPoint(CppUnitMini::TestThread_) ../tests/cppunit/thread.cpp:39
#8 0x7f9ff38b5c0b in void boost::_bi::list1<boost::_bi::valueCppUnitMini::TestThread_ >::operator()<void ()(CppUnitMini::TestThread), boost::bi::list0>(boost::bi::type, void (&)(CppUnitMini::TestThread), boost::_bi::list0&, int) /home/khizmax/works/lib/boost_1_58_0/boost/bind/bind.hpp:253
#9 0x7f9ff38b5c0b in boost::_bi::bind_t<void, void ()(CppUnitMini::TestThread), boost::_bi::list1<boost::_bi::valueCppUnitMini::TestThread* > >::operator()() /home/khizmax/works/lib/boost_1_58_0/boost/bind/bind.hpp:893
#10 0x7f9ff38b5c0b in boost::detail::thread_data<boost::_bi::bind_t<void, void ()(CppUnitMini::TestThread), boost::_bi::list1<boost::_bi::valueCppUnitMini::TestThread* > > >::run() /home/khizmax/works/lib/boost_1_58_0/boost/thread/detail/thread.hpp:116
#11 0x7f9ff38c7a2a in thread_proxy (/home/khizmax/works/cds-2-linux/bin/gcc-5-asan-amd64-linux-64/cdsu-queue+0x7b4a2a)

Direct leak of 1600000 byte(s) in 100000 object(s) allocated from:
#0 0x7f9ff2018c4a in operator new(unsigned long) ../../../../gcc-5.3.0/libsanitizer/asan/asan_new_delete.cc:60
#1 0x7f9ff356dc9f in allocate /home/khizmax/bin/gcc-5.3/include/c++/5.3.0/ext/new_allocator.h:104
#2 0x7f9ff356dc9f in New<queue::(anonymous namespace)::Value> ../cds/details/allocator.h:73
#3 0x7f9ff356dc9f in enqueue ../cds/container/cache_aware_queue.h:121
#4 0x7f9ff356dc9f in enqueue ../cds/container/cache_aware_queue.h:216
#5 0x7f9ff356dc9f in push ../cds/container/cache_aware_queue.h:231
#6 0x7f9ff356dc9f in test ../tests/unit/queue/queue_reader_writer.cpp:105
#7 0x7f9ff38b5810 in CppUnitMini::TestThread::run() ../tests/cppunit/thread.cpp:53
#8 0x7f9ff38b59da in CppUnitMini::TestThread::threadEntryPoint(CppUnitMini::TestThread_) ../tests/cppunit/thread.cpp:39
#9 0x7f9ff38b5c0b in void boost::_bi::list1<boost::_bi::valueCppUnitMini::TestThread_ >::operator()<void ()(CppUnitMini::TestThread), boost::bi::list0>(boost::bi::type, void (&)(CppUnitMini::TestThread), boost::_bi::list0&, int) /home/khizmax/works/lib/boost_1_58_0/boost/bind/bind.hpp:253
#10 0x7f9ff38b5c0b in boost::_bi::bind_t<void, void ()(CppUnitMini::TestThread), boost::_bi::list1<boost::_bi::valueCppUnitMini::TestThread* > >::operator()() /home/khizmax/works/lib/boost_1_58_0/boost/bind/bind.hpp:893
#11 0x7f9ff38b5c0b in boost::detail::thread_data<boost::_bi::bind_t<void, void ()(CppUnitMini::TestThread), boost::_bi::list1<boost::_bi::valueCppUnitMini::TestThread* > > >::run() /home/khizmax/works/lib/boost_1_58_0/boost/thread/detail/thread.hpp:116
#12 0x7f9ff38c7a2a in thread_proxy (/home/khizmax/works/cds-2-linux/bin/gcc-5-asan-amd64-linux-64/cdsu-queue+0x7b4a2a)

Direct leak of 1600000 byte(s) in 100000 object(s) allocated from:
#0 0x7f9ff2018c4a in operator new(unsigned long) ../../../../gcc-5.3.0/libsanitizer/asan/asan_new_delete.cc:60
#1 0x7f9ff356cff3 in allocate /home/khizmax/bin/gcc-5.3/include/c++/5.3.0/ext/new_allocator.h:104
#2 0x7f9ff356cff3 in New<queue::(anonymous namespace)::Value> ../cds/details/allocator.h:73
#3 0x7f9ff356cff3 in enqueue ../cds/container/cache_aware_queue.h:121
#4 0x7f9ff356cff3 in enqueue ../cds/container/cache_aware_queue.h:216
#5 0x7f9ff356cff3 in push ../cds/container/cache_aware_queue.h:231
#6 0x7f9ff356cff3 in test ../tests/unit/queue/queue_reader_writer.cpp:105
#7 0x7f9ff38b5810 in CppUnitMini::TestThread::run() ../tests/cppunit/thread.cpp:53
#8 0x7f9ff38b59da in CppUnitMini::TestThread::threadEntryPoint(CppUnitMini::TestThread_) ../tests/cppunit/thread.cpp:39
#9 0x7f9ff38b5c0b in void boost::_bi::list1<boost::_bi::valueCppUnitMini::TestThread_ >::operator()<void ()(CppUnitMini::TestThread), boost::bi::list0>(boost::bi::type, void (&)(CppUnitMini::TestThread), boost::_bi::list0&, int) /home/khizmax/works/lib/boost_1_58_0/boost/bind/bind.hpp:253
#10 0x7f9ff38b5c0b in boost::_bi::bind_t<void, void ()(CppUnitMini::TestThread), boost::_bi::list1<boost::_bi::valueCppUnitMini::TestThread* > >::operator()() /home/khizmax/works/lib/boost_1_58_0/boost/bind/bind.hpp:893
#11 0x7f9ff38b5c0b in boost::detail::thread_data<boost::_bi::bind_t<void, void ()(CppUnitMini::TestThread), boost::_bi::list1<boost::_bi::valueCppUnitMini::TestThread* > > >::run() /home/khizmax/works/lib/boost_1_58_0/boost/thread/detail/thread.hpp:116
#12 0x7f9ff38c7a2a in thread_proxy (/home/khizmax/works/cds-2-linux/bin/gcc-5-asan-amd64-linux-64/cdsu-queue+0x7b4a2a)

SUMMARY: AddressSanitizer: 6400000 byte(s) leaked in 400000 allocation(s).

@khizmax
Copy link
Owner

khizmax commented Feb 3, 2016

ThreadSanitizer обнаруживает гонки:
http://pastebin.com/tZAT1Cpd

info.head / info.tail должны быть atomic

@DadabaevV
Copy link

После проверки объектов и операций над ними попадающих под подозрения на гонки данных, гонок как таковых не обнаружил. Предупреждения связаны с CAS алгоритмикой.

@hardened-steel
Copy link
Author

Это был мой курсач =)

@khizmax
Copy link
Owner

khizmax commented Jan 31, 2017

Во, пошла дискуссия, это хорошо ;-)
@DadabaevV: если вы взялись довести pull-request по завершения, то было бы неплохо для начала согласоваться с текущей версией ветки master. В сегодняшней версии этот pull-request незаливаем в master.

@khizmax khizmax closed this Oct 28, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants