I built a datastrucuture which I called BufferedQueue. It's
essentially a double buffered queue but instead of two buffers I allow
a user specified number of buffers. Each buffer is a struct which
contains the managed_mapped_file for the particular buffer and a
pointer to a boost::interprocess::deque. Each mapped file contains
only 1 deque and the deque is used to store items pushed onto the
queue by the user. I automatically handle rotation between the
various buffers when the user calls push or pop.
Specific problem:
All of my functional unit tests pass without issue and I have 100%
test coverage. When I run the multi-threaded unit tests I encounter a
segfault, but not immediately. I have some tests which will spawn one
thread which instantiates the datastrucutre and will push 100K items
onto the queue (this will span multiple buffers). I spawn a second
thread which also instantiates the datastrucutre and begin to pop
items off of the queue. After about 40K items have been poped off of
the queue I get a segfault when calling
boost::interprocess::deque::pop_front(). It's always on the same
line, and occurs when the segment manager is doing it's sanity checks
while de-allocating the memory. Sometimes this occurs when it's the
last item in the deque which is being poped, sometimes it's not; there
is no detectable pattern. For my test I'm also using ints so I'm not
pushing something onto the datastrucutre that isn't compatible with
boost::interprocess.
Any helpful ideas as to what may be the cause of my problem would be greatly appreciated.
// Type declarations for the deque
typedef boost::interprocess::managed_mapped_file ManagedFile;
typedef ManagedFile::segment_manager SegmentManager;
typedef typename boost::interprocess::allocator<T, SegmentManager> TypeAllocator;
typedef typename boost::interprocess::list<T, TypeAllocator> MMContainer;
// instantiation of the deque
queue = file.find_or_construct<MMContainer>(getBufferName(name, buffNum).c_str())(TypeAllocator(file.get_segment_manager()));
// my pop method
template<class T>
void
BufferedQueue<T>::pop()
{
checkBufferCount();
{
boost::interprocess::sharable_lock<Mutex> master_lock(*m_masterMutex);
boost::interprocess::scoped_lock<typename Buffer<T>::Mutex> lock(*getReadBuffer().mutex);
assert(getReadBuffer().queue);
if (!isBufferEmpty<T>(getReadBuffer()))
{
assert(!getReadBuffer().queue->empty());
getReadBuffer().queue->pop_front();
return;
}
}
rotate_reader();
boost::interprocess::sharable_lock<Mutex> master_lock(*m_masterMutex);
boost::interprocess::scoped_lock<typename Buffer<T>::Mutex> lock(*getReadBuffer().mutex);
if (isBufferEmpty<T>(getReadBuffer()))
throw Exception("called pop() on an empty buffer");
assert(!getReadBuffer().queue->empty());
getReadBuffer().queue->pop_front();
}
/libs2/external/boost/boost/interprocess/mem_algo/rbtree_best_fit.hpp:1244: void boost::interprocess::rbtree_best_fit<MutexFamily, VoidMutex, MemAlignment>::priv_deallocate(void*) [with MutexFamily = boost::interprocess::mutex_family, VoidPointer = boost::interprocess::offset_ptr<void>, unsigned int MemAlignment = 0u]: Assertion `priv_is_allocated_block(block)' failed.
#0 0x0094a410 in __kernel_vsyscall ()
#1 0x02850df0 in raise () from /lib/libc.so.6
#2 0x02852701 in abort () from /lib/libc.so.6
#3 0x0284a26b in __assert_fail () from /lib/libc.so.6
#4 0x0806ca9f in boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void>, 0u>::priv_deallocate (this=0xb5fcd004, addr=0xb5fcd0b8)
at /libs2/external/boost/boost/interprocess/mem_algo/rbtree_best_fit.hpp:1244
#5 0x0807b00b in boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void>, 0u>::deallocate (this=0xb5fcd004, addr=0xb5fcd0b8)
at /libs2/external/boost/boost/interprocess/mem_algo/rbtree_best_fit.hpp:1233
#6 0x0807b05f in boost::interprocess::segment_manager_base<boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void>, 0u> >::deallocate
(this=0xb5fcd004, addr=0xb5fcd0b8) at /libs2/external/boost/boost/interprocess/segment_manager.hpp:217
#7 0x0807b5fe in boost::interprocess::allocator<boost::container::containers_detail::list_node<int, boost::interprocess::offset_ptr<void> >, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void>, 0u>, boost::interprocess::iset_index> >::deallocate (this=0xb5fcd0b0, ptr=...)
at /libs2/external/boost/boost/interprocess/allocators/allocator.hpp:152
#8 0x0807b61c in boost::interprocess::allocator<boost::container::containers_detail::list_node<int, boost::interprocess::offset_ptr<void> >, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void>, 0u>, boost::interprocess::iset_index> >::deallocate_one (this=0xb5fcd0b0, p=...)
at /libs2/external/boost/boost/interprocess/allocators/allocator.hpp:234
#9 0x0807b693 in boost::container::containers_detail::allocator_destroyer<boost::interprocess::allocator<boost::container::containers_detail::list_node<int, boost::interprocess::offset_ptr<void> >, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void>, 0u>, boost::interprocess::iset_index> > >::priv_deallocate (this=0x43511dc, p=...) at /libs2/external/boost/boost/interprocess/containers/container/detail/destroyers.hpp:133
#10 0x0807b6ca in boost::container::containers_detail::allocator_destroyer<boost::interprocess::allocator<boost::container::containers_detail::list_node<int, boost::interprocess::offset_ptr<void> >, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void>, 0u>, boost::interprocess::iset_index> > >::operator() (this=0x43511dc, p=...) at /libs2/external/boost/boost/interprocess/containers/container/detail/destroyers.hpp:143
#11 0x0807b786 in boost::intrusive::list_impl<boost::intrusive::listopt<boost::intrusive::detail::base_hook_traits<boost::container::containers_detail::list_node<int, boost::interprocess::offset_ptr<void> >, boost::intrusive::list_node_traits<boost::interprocess::offset_ptr<void> >, normal_link, boost::intrusive::default_tag, 1>, unsigned int, true> >::erase_and_dispose<boost::container::containers_detail::allocator_destroyer<boost::interprocess::allocator<boost::container::containers_detail::list_node<int, boost::interprocess::offset_ptr<void> >, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void>, 0u>, boost::interprocess::iset_index> > > > (
this=0xb5fcd0b4, i=..., disposer=...) at /libs2/external/boost/boost/intrusive/list.hpp:649
#12 0x0807b7ce in boost::intrusive::list_impl<boost::intrusive::listopt<boost::intrusive::detail::base_hook_traits<boost::container::containers_detail::list_node<int, boost::interprocess::offset_ptr<void> >, boost::intrusive::list_node_traits<boost::interprocess::offset_ptr<void> >, normal_link, boost::intrusive::default_tag, 1>, unsigned int, true> >::erase_and_dispose<boost::container::containers_detail::allocator_destroyer<boost::interprocess::allocator<boost::container::containers_detail::list_node<int, boost::interprocess::offset_ptr<void> >, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void>, 0u>, boost::interprocess::iset_index> > > > (
this=0xb5fcd0b4, i=..., disposer=...) at /libs2/external/boost/boost/intrusive/list.hpp:656
#13 0x0807b839 in boost::container::list<int, boost::interprocess::allocator<int, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void>, 0u>, boost::interprocess::iset_index> > >::erase (this=0xb5fcd0b0, p=...)
at /libs2/external/boost/boost/interprocess/containers/container/list.hpp:930
#14 0x0807b881 in boost::container::list<int, boost::interprocess::allocator<int, boost::interprocess::segment_manager<char, boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family, boost::interprocess::offset_ptr<void>, 0u>, boost::interprocess::iset_index> > >::pop_front (this=0xb5fcd0b0)
at /libs2/external/boost/boost/interprocess/containers/container/list.hpp:623
#15 0x0808a2e2 in Ovid::BufferedQueue<int>::pop (this=0x43512f0) at /ovid/server/shared/ovidserver-bufferedqueue.cpp:287
#16 0x080557fb in reader_multithread_two_writer_single_reader_throughput () at test-ovidserver-bufferedqueue.cpp:389
#17 0x07653832 in start_thread () from /lib/libpthread.so.0
#18 0x028f9e0e in clone () from /lib/libc.so.6