Search code examples
c++c++11boosttbbboost-graph

Changing container generator in boost graph adjacency list using custom container concurrent vector


Note

Please remove the duplicate mark for this question. Although the error was due to missing -ltbb flags, the main motive of the question was how to change the container_generator in boost graph to use your own specific container such as concurrent vector as provided by TBB. People may ignore the answered question because it is marked duplicate.


I was trying to define my custom container for my boost adjacency_list<> typedef. As per the documentation here, I tried to use tbb::concurrent_vector<> as my custom container. Here is my code, and I get the following error:

#include <boost/graph/adjacency_list.hpp>
#include "tbb/concurrent_vector.h"

struct concVecS { };

namespace boost {
template <class ValueType>
    struct container_gen<concVecS, ValueType> {
    //typedef std::list<ValueType> type;
    typedef tbb::concurrent_vector<ValueType> type;
};

template<>
struct parallel_edge_traits<concVecS > {
    typedef allow_parallel_edge_tag type;
};

}

typedef boost::adjacency_list <concVecS, boost::vecS, boost::directedS> MyGraph;

int main(int, char*[]) 
{
    MyGraph g(5);

    return 0;
}

Error:

/tmp/cc3YbTER.o: In function tbb::concurrent_vector<boost::detail::sep_<unsigned long, boost::no_property>, tbb::cache_aligned_allocator<boost::detail::sep_<unsigned long, boost::no_property> > >::~concurrent_vector()': /cm/shared/apps/intel-tbb-oss/intel64/42_20131003oss/include/tbb/concurrent_vector.h:888: undefined reference to tbb::internal::concurrent_vector_base_v3::internal_clear(void ()(void, unsigned long))' /cm/shared/apps/intel-tbb-oss/intel64/42_20131003oss/include/tbb/concurrent_vector.h:890: undefined reference to tbb::internal::concurrent_vector_base_v3::~concurrent_vector_base_v3()' /cm/shared/apps/intel-tbb-oss/intel64/42_20131003oss/include/tbb/concurrent_vector.h:890: undefined reference to tbb::internal::concurrent_vector_base_v3::~concurrent_vector_base_v3()' /tmp/cc3YbTER.o: In function tbb::cache_aligned_allocator<boost::detail::sep_<unsigned long, boost::no_property> >::deallocate(boost::detail::sep_<unsigned long, boost::no_property>*, unsigned long)': /cm/shared/apps/intel-tbb-oss/intel64/42_20131003oss/include/tbb/cache_aligned_allocator.h:96: undefined reference totbb::internal::NFS_Free(void*)' /tmp/cc3YbTER.o: In function tbb::cache_aligned_allocator<boost::detail::sep_<unsigned long, boost::no_property> >::allocate(unsigned long, void const*)': /cm/shared/apps/intel-tbb-oss/intel64/42_20131003oss/include/tbb/cache_aligned_allocator.h:91: undefined reference totbb::internal::NFS_Allocate(unsigned long, unsigned long, void*)' collect2: error: ld returned 1 exit status

I dont know what wrong I am doing. I changed the container to std::list and it works fine. Dont know what is it I have to add more. as per documentation, this is enough atleast to create a simple graph object.


Solution

  • Thanks to the comments provided by Dr. Jeremy Siek at this link here, I was able to define my own container type viz. concurrent_vector to the container_traits.hpp file in boost/pending/ folder.

    I can now change the vecS to concurrentVecS and use my algorithm. Although std::vector<> is thread safe for reads, I wanted to try this with concurrent vector.

    Here is the completed code.

    //in container_traits.hpp  --> added the following code 
    //boost/pending/container_traits.hpp  file
    
    //concurrent vector
    struct concurrent_vector_tag :
      virtual public random_access_container_tag,
      virtual public back_insertion_sequence_tag {  };
    
    template <class T, class Alloc>
    concurrent_vector_tag  container_category(const tbb::concurrent_vector<T, Alloc>&) {
      return concurrent_vector_tag();
    }
    
    template <class T, class Alloc>
    unstable_tag  iterator_stability(const tbb::concurrent_vector<T, Alloc>&) {
      return unstable_tag();
    }
    
     #if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION 
     template <class T, class Alloc>
     struct container_traits< tbb::concurrent_vector <T, Alloc> > {
       typedef  concurrent_vector_tag  category;
       typedef  unstable_tag  iterator_stability;
     };
     #endif
    
    
     //in my custom_container.hpp file     
    #include "tbb/concurrent_vector.h"
    #include <boost/graph/adjacency_list.hpp>
    
    namespace boost {
    
    struct cvecS {  };  //concurrent vector selector
    
    template <class ValueType>
    struct container_gen <cvecS, ValueType> {
        typedef tbb::concurrent_vector <ValueType> type;
    };
    
    template<>
    struct parallel_edge_traits<cvecS > {
      typedef allow_parallel_edge_tag type;
    };
    
    }; //namespace
    
    
    
    // in my main file 
    typedef boost::adjacency_list <boost::cvecS, boost::cvecS, boost::undirectedS> Graph_t
    
    Graph_t g (5);
    Graph_t::vertex_descriptor v1, v2; 
     v1 = boost::add_vertex(g); 
     v2 = boost::add_vertex(g);
     boost::add_edge(v1, v2, g);
    

    PS: I am not sure, but I am guessing, there was no need to add push() and erase() functions in this case as concurrent_vector.h file already provides them.