工作中用到了tbb::concurrent_hash_map,但是同时用到了boost的serialize,boost没有提供对tbb::concurrent_hash_map的序列化支持,因此自己参考boost对stl中hash_map的实现,实现了使用boost库序列化tbb::concurrent_hash_map。本人水平有限,boost中hash_map序列化相关代码未完全看透,下面代码不保证在各种环境的可靠性。如果文中有错误,欢迎不吝指点。
实现文件:concurrent_hash_map.hpp
#ifndef _CONCURRENT_HASH_MAP_HPP_
#define _CONCURRENT_HASH_MAP_HPP_
#include "tbb/concurrent_hash_map.h"
#include
#include
#include
#include
namespace boost
{
namespace serialization
{
namespace tbb
{
template
struct archive_input_hash_map
{
inline void operator()(
Archive &ar,
Container &s,
const unsigned int v
){
typedef typename Container::value_type type;
detail::stack_construct t(ar, v);
// borland fails silently w/o full namespace
ar >> boost::serialization::make_nvp("item", t.reference());
//-▽-modified by me 2016/1/20---------//
Container::accessor a;
bool bResult = s.insert(a, t.reference());
//std::pair result =
// s.insert(t.reference());
// note: the following presumes that the map::value_type was NOT tracked
// in the archive. This is the usual case, but here there is no way
// to determine that.
//if (result.second){
// ar.reset_object_address(
// &(result.first->second),
// &t.reference().second
// );
//}
if (bResult)
{
ar.reset_object_address(
&(a->second),
&t.reference().second
);
}
//-△-modified by me 2016/1/20----------//
}
};
template
inline void save_hash_collection(Archive & ar, const Container &s)
{
collection_size_type count(s.size());
const collection_size_type bucket_count(s.bucket_count());
const item_version_type item_version(
version::value
);
#if 0
/* should only be necessary to create archives of previous versions
* which is not currently supported. So for now comment this out
*/
boost::archive::library_version_type library_version(
ar.get_library_version()
);
// retrieve number of elements
if (boost::archive::library_version_type(6) != library_version){
ar << BOOST_SERIALIZATION_NVP(count);
ar << BOOST_SERIALIZATION_NVP(bucket_count);
}
else{
// note: fixup for error in version 6. collection size was
// changed to size_t BUT for hashed collections it was implemented
// as an unsigned int. This should be a problem only on win64 machines
// but I'll leave it for everyone just in case.
const unsigned int c = count;
const unsigned int bc = bucket_count;
ar << BOOST_SERIALIZATION_NVP(c);
ar << BOOST_SERIALIZATION_NVP(bc);
}
if (boost::archive::library_version_type(3) < library_version){
// record number of elements
// make sure the target type is registered so we can retrieve
// the version when we load
ar << BOOST_SERIALIZATION_NVP(item_version);
}
#else
ar << BOOST_SERIALIZATION_NVP(count);
ar << BOOST_SERIALIZATION_NVP(bucket_count);
ar << BOOST_SERIALIZATION_NVP(item_version);
#endif
typename Container::const_iterator it = s.begin();
while (count-- > 0){
// note borland emits a no-op without the explicit namespace
boost::serialization::save_construct_data_adl(
ar,
&(*it),
boost::serialization::version<
typename Container::value_type
>::value
);
ar << boost::serialization::make_nvp("item", *it++);
}
}
template
inline void load_hash_collection(Archive & ar, Container &s)
{
collection_size_type count;
collection_size_type bucket_count;
boost::serialization::item_version_type item_version(0);
boost::archive::library_version_type library_version(
ar.get_library_version()
);
// retrieve number of elements
if (boost::archive::library_version_type(6) != library_version){
ar >> BOOST_SERIALIZATION_NVP(count);
ar >> BOOST_SERIALIZATION_NVP(bucket_count);
}
else{
// note: fixup for error in version 6. collection size was
// changed to size_t BUT for hashed collections it was implemented
// as an unsigned int. This should be a problem only on win64 machines
// but I'll leave it for everyone just in case.
unsigned int c;
unsigned int bc;
ar >> BOOST_SERIALIZATION_NVP(c);
count = c;
ar >> BOOST_SERIALIZATION_NVP(bc);
bucket_count = bc;
}
if (boost::archive::library_version_type(3) < library_version){
ar >> BOOST_SERIALIZATION_NVP(item_version);
}
s.clear();
#if ! defined(__MWERKS__)
//s.resize(bucket_count); //delete by me 2016/1/20
#endif
InputFunction ifunc;
while (count-- > 0){
ifunc(ar, s, item_version);
}
}
}
}
}
template<
class Archive,
class Key,
class HashFcn,
class EqualKey,
class Allocator
>
inline void serialize( Archive & ar
, tbb::concurrent_hash_map &t,
const unsigned int file_version)
{
boost::serialization::split_free(ar, t, file_version);
}
template<
class Archive,
class Key,
class HashFcn,
class EqualKey,
class Allocator
>
inline void save(
Archive & ar,
const tbb::concurrent_hash_map <
Key, HashFcn, EqualKey, Allocator
> &t,
const unsigned int file_version
){
boost::serialization::tbb::save_hash_collection <
Archive,
tbb::concurrent_hash_map<
Key, HashFcn, EqualKey, Allocator
>
> (ar, t);
}
template<
class Archive,
class Key,
class HashFcn,
class EqualKey,
class Allocator
>
inline void load(
Archive & ar,
tbb::concurrent_hash_map<
Key, HashFcn, EqualKey, Allocator
> &t,
const unsigned int file_version
){
boost::serialization::tbb::load_hash_collection <
Archive,
tbb::concurrent_hash_map<
Key, HashFcn, EqualKey, Allocator
>,
boost::serialization::tbb::archive_input_hash_map <
Archive,
tbb::concurrent_hash_map<
Key, HashFcn, EqualKey, Allocator
>
>
> (ar, t);
}
#endif _CONCURRENT_HASH_MAP_HPP_
#include "stdafx.h"
#include
#include
#include
#include
#include "boost/archive/binary_iarchive.hpp"
#include "boost/archive/binary_oarchive.hpp"
#include "tbb/concurrent_hash_map.h"
#include "concurrent_hash_map.hpp"
struct tbb_hash_func //hash 函数
{
// 取hash value
static size_t hash( std::string str)
{
std::hash hash_fn;
return hash_fn(std::string(str));
}
static bool equal(const std::string str1, const std::string str2)
{
return memcmp(&str1, &str2, sizeof(str2)) == 0 ? true : false;
}
};
typedef tbb::concurrent_hash_map Int_TableType;
typedef tbb::concurrent_hash_map < std::string, std::string, tbb_hash_func >String_TableType;
void write_test()
{
std::fstream file("Text.big", std::ios::binary | std::ios::out);
Int_TableType Table;
Int_TableType::accessor a;
Table.insert(a, Int_TableType::value_type(std::string("First"), 1));
Table.insert(a, Int_TableType::value_type(std::string("Second"), 2));
Table.insert(a, Int_TableType::value_type(std::string("Third"), 3));
Table.insert(a, Int_TableType::value_type(std::string("Fourth"), 4));
Table.insert(a, Int_TableType::value_type(std::string("Fifth"), 5));
Table.insert(a, Int_TableType::value_type(std::string("Sixth"), 6));
Table.insert(a, Int_TableType::value_type(std::string("Seventh"), 7));
for (int i = 0; i < 1000; ++i)
{
if ( i<200)
Table.insert(a, Int_TableType::value_type(std::string("X"), 8 + i));
else if ( i>=200 && i<400 )
Table.insert(a, Int_TableType::value_type(std::string("S"), 8 + i));
else if ( i>=400 && i<600 )
Table.insert(a, Int_TableType::value_type(std::string("Y"), 8 + i));
else if ( i>=600 && i<800 )
Table.insert(a, Int_TableType::value_type(std::string("Z"), 8 + i));
else if (i>=800 )
Table.insert(a, Int_TableType::value_type(std::string("W"), 8 + i));
}
Int_TableType::iterator it = Table.begin();
for (; it != Table.end(); ++it)
{
std::cout << it->first << "---" << it->second << std::endl;
}
std::cout << "SIZE:"<< Table.size() << std::endl;
boost::archive::binary_oarchive os(file);
os << Table;
file.close();
}
void read_test()
{
std::fstream file("Text.big", std::ios::binary | std::ios::in);
Int_TableType Table;
boost::archive::binary_iarchive is(file);
is >> Table;
std::cout << "-------------------------------------------" << std::endl;
Int_TableType::iterator it = Table.begin();
for (; it != Table.end(); ++it)
{
std::cout << it->first << "---" << it->second << std::endl;
}
std::cout << "SIZE:" << Table.size() << std::endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
write_test();
read_test();
system("pause");
return 0;
}